很多人写关于线程的时候都是写一堆原理在开头。我不讲,因为我讲不好。废话不多说直接看代码。
Java的Thead类就是Java实现线程的载体。为啥是Thread。没这么多为什么,是张三还是李四不总得有个名吗。
Java有个约定,写个类有个main方法,这个类就可以直接run,入口就是这个main方法。main方法执行的时候Jvm无形中就启动了一个线程来执行要干得事,这个无形的线程可以通过Thread类提供的静态方法拿到。我们来看一段代码:
执行结果:
看到没有,真的有个无形的线程,而且这个线程的名字就叫main。这个方法你无论执行执行多少次,结果都是一样的。因为这是Java默认的。
既然知道了Java的代码执行时总是在一个线程里,那我们来看看这个线程类Thread到底是什么个玩意。
这里提供了一个信息,Thread类是一个实现了Runnable接口的类,我们先记着。
然后我们看下Thread提供了哪些方法来方便你做事。我们再来逐个讲解其用法:
1、public synchronized void start() 启动线程的方法。调用本地方法start0()来告诉jvm线程一准就绪,可以调run方法来执行来。
2、public void run() 执行向线程提交的任务。
3、public void interrupt() 用于主动中断线程。
4、public static boolean interrupted() 清除线程的中断状态,如果线程调用此方法前是中断的,则清除其中断状态,并且返回ture,否则返回false。
5、public boolean isInterrupted() 获取线程当前中断状态,true代表中断
6、public final native boolean isAlive 获取线程的存活状态
7、public static int activeCount() 获取线程活动的数量,因为一个线程在执行期间可以创建线程,这些线程会记录在当前线程维护的一个线程组内,包括当前线程也在内。这个方法获取到的最小值为1.
8、public static native Thread currentThread() 本地静态方法,获取当前执行线程对应的Thread类实例
9、public static native void yield(); 本地静态方法,让当前正在执行的线程让出CPU,让其他线程执行。
10、public static native void sleep(long millis);让当前线程暂停执行若干毫秒。我们通常写demo会用此方法模拟一个耗时操作。此方法不会让出当前执行线程占用的CPU。
11、public static void sleep(long millis, int nanos) 作用同方法13,看了下源码感觉没什么用。
12、public final synchronized void join(long millis) 用与线程协作,例如。我有两件事情A、B,A可能需要先执行一段时间,才会用到B的结果,B是完全独立的。此时就可以分别启动A、B两个线程来做事。A中使用B.join方法。假设A认为5秒内B可以执行完,那就使用B.join(5000)。等B5秒钟。5秒种后不管B执行怎么养了A继续执行。如果一定要得到B的结果,可直接使用B.join()或者B.join(0),代表永久等待,直至B结束任务。
13、public final synchronized void join(long millis, int nanos) 等同于方法12
14、public final void join() 等同与直接用方法12 join(0);
其他一些,直接对属性操作的方法我们就不列举了。
我们主要来针对这14个方法来探究下:
1、start方法已在介绍方法时说明,此处就不在说了
2、run方法,此方法源码很简单,就是调用传入的Runnable任务的run方法。
3、interrupt,interrupted,isInterrupted方法探究。
我们可以看到,interrupt方法将线程标记为了中断,这只是状态上发生了变化,实际线程并没有停止,还是正常的被执行了,所以中断不等于线程停止,它只是一个标记了一个线程状态。我们也看到了isInterrupted可以获取到线程中断状态,interrupted也可以获得线程的中断状态,只不过它知道线程的状态是中断时会清除这个状态。
我们从运行结果来看,interrupt对线程只是做了中断标记,事实上什么也没干啊。那它有什么意义。别急我们再把这个方法改造下:
可以看到,如果线程被中断了,尝试调用线程的sleep方法会触发中断异常。触发中断异常后,会清除线程的中断状态。当然并不单单sleep方法会触发。join方法和wait方法都会产生这样的效果。
知道了它我们可以针对灵活的作出设计。尤其在线程之间协作时。
4、join方法探究:
从结果来看,任务一完成需要6秒钟,为什么是6秒而不是7秒,说明了任务2和任务1同时执行了1秒钟。任务一等任务2,用了4秒钟。
我们再来修改下任务一:
分析一下:任务一执行用4秒,其中两秒是用在了等待任务二执行。但是任务二在等待了两秒后并没有执行完成。所以等1执行完成后,二才执行完成。
线程的方法稍微难理解的就这几个,其他的都很容易理解,而且在演示代码中也都用了下,如果感兴趣,可自行尝试。