「java线程专题」java线程详解
本篇文章给大家谈谈java线程专题,以及java线程详解对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。
本文目录一览:
Java多线程编程基础之线程对象
; 在进入java平台的线程对象之前 基于基础篇(一)的一些问题 我先插入两个基本概念 线程的并发与并行 在单CPU系统中 系统调度在某一时刻只能让一个线程运行 虽然这种调试机制有多种形式(大多数是时间片轮巡为主) 但无论如何 要通过不断切换需要运行的线程让其运行的方式就叫并发(concurrent) 而在多CPU系统中 可以让两个以上的线程同时运行 这种可以同时让两个以上线程同时运行的方式叫做并行(parallel) 在上面包括以后的所有论述中 请各位朋友谅解 我无法用最准确的词语来定义储如并发和并行这类术语 但我以我的经验能通俗地告诉大家它是怎么一回事 如果您看到我说的一些 标准 文档上说的不一样 只要意思一致 那您就不要挑刺了 Java线程对象 现在我们来开始考察JAVA中线程对象 在JAVA中 要开始一个线程 有两种方式 一是直接调用Thread实例的start()方法 二是 将Runable实例传给一个Thread实例然后调用它的start()方法 在前面已经说过 线程对象和线程是两个完全不同的概念 这里我们再次深入一下 生成一个线程的实例 并不代表启动了线程 而启动线程是说在某个线程对象上启动了该实例对应的线程 当该线程结束后 并不会就立即消失 对于从很多书籍上可以看到的基础知识我就不用多说了 既然是基础知识 我也着重于从普通文档上读不到的内容 所以本节我重点要说的是两种线程对象产生线程方式的区别 class MyThread extends Thread{ public int x = ; public void run(){ for(int i= ;i ;i++){ try{ Thread sleep( ) }catch(Exception e){} System out println(x++) } } } 如果我们生成MyThread的一个实例 然后调用它的start()方法 那么就产生了这个实例对应的线程 public class Test { public static void main(String[] args) throws Exception{ MyThread mt = new MyThread() mt start() } } 不用说 最终会打印出 到 现在我们稍微玩一点花样 public class Test { public static void main(String[] args) throws Exception{ MyThread mt = new MyThread() mt start() System out println( ) } } 也不用说 在基础篇(一)中我们知道由于单CPU的原因 一般会先打印 然后打印 到 不过我们可以控制线程让它按我们的意思来运行 public class Test { public static void main(String[] args) throws Exception{ MyThread mt = new MyThread() mt start() mt join() System out println( ) } } 好了 我们终于看到 mt实例对应的线程(假如我有时说mt线程请你不要怪我 不过我尽量不这么说) 在运行完成后 主线程才打印 因为我们让当前线程(这里是主线程)等待mt线程的运行结束 在线程对象a上调用join()方法 就是让当前正在执行的线程等待线程对象a对应的线程运行完成后才继续运行 请大家一定要深刻理解并熟记这句话 而我这里引出这个知识点的目的是为了让你继续看下面的例子 public class Test { public static void main(String[] args) throws Exception{ MyThread mt = new MyThread() mt start() mt join() Thread sleep( ) mt start() } } 当线程对象mt运行完成后 我们让主线程休息一下 然后我们再次在这个线程对象上启动线程 结果我们看到 Exception in thread main java lang IllegalThreadStateException 也就是这种线程对象一时运行一次完成后 它就再也不能运行第二次了 我们可以看一下它有具体实现 public synchronized void start() { if (started) throw new IllegalThreadStateException() started = true; group add(this) start () } 一个Thread的实例一旦调用start()方法 这个实例的started标记就标记为true 事实中不管这个线程后来有没有执行到底 只要调用了一次start()就再也没有机会运行了 这意味着 通过Thread实例的start() 一个Thread的实例只能产生一个线程 那么如果要在一个实例上产生多个线程(也就是我们常说的线程池) 我们应该如何做呢?这就是Runnable接口给我们带来的伟大的功能 class R implements Runnable{ private int x = ; public void run(){ for(int i= ;i ;i++){ try{ Thread sleep( ) }catch(Exception e){} System out println(x++) } } } 正如它的名字一样 Runnable的实例是可运行的 但它自己并不能直接运行 它需要被Thread对象来包装才行运行 public class Test { public static void main(String[] args) throws Exception{ new Thread(new R()) start() } } 当然这个结果和mt start()没有什么区别 但如果我们把一个Runnable实例给Thread对象多次包装 我们就可以看到它们实际是在同一实例上启动线程 public class Test { public static void main(String[] args) throws Exception{ R r = new R() for(int i= ;i ;i++) new Thread(r) start() } } x是实例对象 但结果是x被加到了 说明这 个线程是在同一个r对象上运行的 请大家注意 因为这个例子是在单CPU上运行的 所以没有对多个线程同时操作共同的对象进行同步 这里是为了说明的方便而简化了同步 而真正的环境中你无法预知程序会在什么环境下运行 所以一定要考虑同步 到这里我们做一个完整的例子来说明线程产生的方式不同而生成的线程的区别 package debug; import java io *; import java lang Thread; class MyThread extends Thread{ public int x = ; public void run(){ System out println(++x) } } class R implements Runnable{ private int x = ; public void run(){ System out println(++x) } } public class Test { public static void main(String[] args) throws Exception{ for(int i= ;i ;i++){ Thread t = new MyThread() t start() } Thread sleep( ) //让上面的线程运行完成 R r = new R() for(int i= ;i ;i++){ Thread t = new Thread(r) t start() } } } 上面 个线程对象产生的 个线程运行时打印了 次 下面 个线程对象产生的 个线程运行时打印了 到 我们把下面的 个线程称为同一实例(Runnable实例)的多个线程 lishixinzhi/Article/program/Java/gj/201311/27500
一道java线程题目
没有同步,m出现了问题。加上synchronized关键字
public synchronized void run() {
for (m = 1; m = 1000;m++) {
if (m % 2 == 1) {
System.out.println("奇数:" + m);
}
try {
Thread.sleep((int) (Math.random() * 100));
} catch (InterruptedException e) {
}
if (m % 2 == 0) {
System.out.println("偶数:" + m);
}
try {
Thread.sleep((int) (Math.random() * 100));
} catch (InterruptedException e) {
}
}
}
Java的线程在项目中一般会有什么具体的应用?
java线程在项目中的应用场景如下:
场景一:一个业务逻辑有很多次的循环,每次循环之间没有影响,比如验证1万条url路径是否存在,正常情况要循环1万次,逐个去验证每一条URL,这样效率会很低,假设验证一条需要1分钟,总共就需要1万分钟,有点恐怖。这时可以用多线程,将1万条URL分成50等份,开50个线程,没个线程只需验证200条,这样所有的线程执行完是远小于1万分钟的。
场景二:需要知道一个任务的执行进度,比如我们常看到的进度条,实现方式可以是在任务中加入一个整型属性变量(这样不同方法可以共享),任务执行一定程度就给变量值加1,另外开一个线程按时间间隔不断去访问这个变量,并反馈给用户。
总之使用多线程就是为了充分利用cpu的资源,提高程序执行效率,当你发现一个业务逻辑执行效率特别低,耗时特别长,就可以考虑使用多线程。不过CPU执行哪个线程的时间和顺序是不确定的,即使设置了线程的优先级,因此使用多线程的风险也是比较大的,会出现很多预料不到的问题,一定要多熟悉概念,多构造不同的场景去测试才能够掌握!
Java多线程是什么意思?
Java多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。
1、继承Thread类实现多线程
继承Thread类的方法尽管被我列为一种多线程实现方式,但Thread本质上也是实现了Runnable接口的一个实例,它代表一个线程的实例,并且,启动线程的唯一方法就是通过Thread类的start()实例方法。start()方法是一个native方法,它将启动一个新线程,并执行run()方法。这种方式实现多线程很简单,通过自己的类直接extend Thread,并复写run()方法,就可以启动新线程并执行自己定义的run()方法。例如:
在合适的地方启动线程如下:
2、实现Runnable接口方式实现多线程
如果自己的类已经extends另一个类,就无法直接extends Thread,此时,必须实现一个Runnable接口,如下:
为了启动MyThread,需要首先实例化一个Thread,并传入自己的MyThread实例:
事实上,当传入一个Runnable target参数给Thread后,Thread的run()方法就会调用target.run(),参考JDK源代码:
3、使用ExecutorService、Callable、Future实现有返回结果的多线程
ExecutorService、Callable、Future这个对象实际上都是属于Executor框架中的功能类。想要详细了解Executor框架的可以访问 ,这里面对该框架做了很详细的解释。返回结果的线程是在JDK1.5中引入的新特征,确实很实用,有了这种特征我就不需要再为了得到返回值而大费周折了,而且即便实现了也可能漏洞百出。
可返回值的任务必须实现Callable接口,类似的,无返回值的任务必须Runnable接口。执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callable任务返回的Object了,再结合线程池接口ExecutorService就可以实现传说中有返回结果的多线程了。下面提供了一个完整的有返回结果的多线程测试例子,在JDK1.5下验证过没问题可以直接使用。代码如下:
代码说明:
上述代码中Executors类,提供了一系列工厂方法用于创先线程池,返回的线程池都实现了ExecutorService接口。
public static ExecutorService newFixedThreadPool(int nThreads)
创建固定数目线程的线程池。
public static ExecutorService newCachedThreadPool()
创建一个可缓存的线程池,调用execute 将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。
public static ExecutorService newSingleThreadExecutor()
创建一个单线程化的Executor。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代Timer类。
总结:ExecutoreService提供了submit()方法,传递一个Callable,或Runnable,返回Future。如果Executor后台线程池还没有完成Callable的计算,这调用返回Future对象的get()方法,会阻塞直到计算完成。
Java多线程编程基础之线程和多线程
随着计算机技术的发展 编程模型也越来越复杂多样化 但多线程编程模型是目前计算机系统架构的最终模型 随着CPU主频的不断攀升 X 架构的硬件已经成为瓶 在这种架构的CPU主频最高为 G 事实上目前 G主频的CPU已经接近了顶峰
如果不能从根本上更新当前CPU的架构(在很长一段时间内还不太可能) 那么继续提高CPU性能的方法就是超线程CPU模式 那么 作业系统 应用程序要发挥CPU的最大性能 就是要改变到以多线程编程模型为主的并行处理系统和并发式应用程序
所以 掌握多线程编程模型 不仅是目前提高应用性能的手段 更是下一代编程模型的核心思想 多线程编程的目的 就是 最大限度地利用CPU资源 当某一线程的处理不需要占用CPU而只和I/O OEMBIOS等资源打交道时 让需要占用CPU资源的其它线程有机会获得CPU资源 从根本上说 这就是多线程编程的最终目的
第一需要弄清的问题
如同程序和进程的区别 要掌握多线程编程 第一要弄清的问题是 线程对象和线程的区别
线程对象是可以产生线程的对象 比如在java平台中Thread对象 Runnable对象 线程 是指正在执行的一个指点令序列 在java平台上是指从一个线程对象的start()开始 运行run方法体中的那一段相对独立的过程
鉴于作者的水平 无法用更确切的词汇来描述它们的定义 但这两个有本质区别的概念请初学者细细体会 随着介绍的深入和例程分析的增加 就会慢慢明白它们所代表的真实含义
天下难事必始于易 天下大事必始于细
让我们先从最简单的 单线程 来入手 ( )带引号说明只是相对而言的单线程 ( )基于java
class BeginClass{ public static void main(String[] args){ for(int i= ;i ;i++) System out println( Hello World! ); } }
如果我们成功编译了该java文件 然后在命令行上敲入
java BeginClass
现在发生了什么呢?每一个java程序员 从他开始学习java的第一分钟里都会接触到这个问题 但是 你知道它到底发生发什么?
JVM进程被启动 在同一个JVM进程中 有且只有一个进程 就是它自己 然后在这个JVM环境中 所有程序的运行都是以线程来运行 JVM最先会产生一个主线程 由它来运行指定程序的入口点 在这个程序中 就是主线程从main方法开始运行 当main方法结束后 主线程运行完成 JVM进程也随之退出
我们看到的是一个主线程在运行main方法 这样的只有一个线程执行程序逻辑的流程我们称
之为单线程 这是JVM提供给我们的单线程环境 事实上 JVM底层还至少有垃圾回收这样的后台线程以及其它非java线程 但这些线程对我们而言不可访问 我们只认为它是单线程的
主线程是JVM自己启动的 在这里它不是从线程对象产生的 在这个线程中 它运行了main方法这个指令序列 理解它 但它没有更多可以研究的内容
接触多线程
class MyThread extends Thread{ public void run(){ System out println( Thread say:Hello World! ); } } public class MoreThreads{ public static void main(String[] args){ new MyThread(); new MyThread() start(); System out println( Main say:Hello World ); } }
执行这个程序 main方法第一行产生了一个线程对象 但并没有线程启动
main方法第二行产生了一个线程对象 并启动了一个线程
main方法第三行 产生并启动一个线程后 主线程自己也继续执行其它语句
lishixinzhi/Article/program/Java/gj/201311/27552
关于java线程专题和java线程详解的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。