1. 线程的介绍
对计算机来说,每一个任务就是一个进程,在每一个进程内部至少要有一个线程是在运行中,有时线程也称为轻量级的进程。
线程是程序执行的一个路径,每一个线程都有自己的局部变量表、程序计数器(指向正在执行的指令指针)以及各自的生命周期。
线程启动必须在其中一个任务之前,否则线程将永远得不到启动,因为前一个任务永远不会结束。
只用调用了Thread的start方法,才代表派生了一个新的线程,否则与普通的Java对象没有任何区别。
2.线程的生命周期
主要分为以下5个主要的阶段:
(1)NEW(初始状态)
用关键字new新创建了一个线程对象,但还没有调用start()方法。
(2)RUNNABLE(可执行状态)
线程对象进入RUNNABLE状态必须调用start方法,可执行状态说明它具备执行的资格,但是并没有真正的执行起来而是等待CPU的调度。
RUNNABLE状态的线程只能意外终止或者进入RUNNING状态。
(3)RUNNING(运行状态)
一个RUNNING状态的线程事实上也是RUNNABLE的,但是反过来不成立。
在该状态中,线程的状态可以发生如下的状态转换:
(4)BLOCKED(阻塞状态)
在该状态的线程可以切换到如下几个状态:
(5)TERMINATED(终止状态)
TERMINATED是一个线程的最终状态,在该状态中线程将不会切换到其他任何状态,也意味着该线程的整个生命周期都结束了。以下情况将会使线程进入TERMINATED状态:
3. 几点结论:
4.守护线程
它是一类比较特殊的线程,一般用于处理一些后台的工作,比如JDK的垃圾回收线程。
在正常情况下,若JVM中没有一个非守护线程,则JVM的进程会退出。
设置守护线程的方法很简单,调用setDaemon方法即可,true代表守护线程,false代表正常线程;setDaemon方法只在线程启动之前才能生效,如果一个线程已经死亡,那么再设置setDaemon则会跑出IllegalThreadStateException异常。
守护线程的作用:
具备自动结束生命周期的特性。当你希望关闭某些线程的时候,或者退出JVM进程的时候,一些线程能够自动关闭,此时就可以考虑用守护线程为你完成这样的工作。
5. 线程sleep
该方法会使当前线程进入指定毫秒数的休眠,暂停执行。休眠有一个重要的特性,那就是其不会放弃monitor所的所有权。
在JDK1.5以后,引入了一个枚举TimeUnit,可以使用它来替代Thread.sleep。因为sleep能做的事,TimeUnit全部都能完成,并且功能更加强大。如下:
6.线程yield
yield方法属于一种启发式的方法,其会提醒调度器我愿意放弃当前的CPU资源,如果CPU的资源不紧张,则会忽略这种提醒。
调用yield方法会使当前线程从RUNNING状态切换到RUNNABLE状态,一般这个方法不太常用。
yield与sleep的区别:
7.设置线程的优先级
理论上是优先级比较高的线程会获取优先被CPU调度的机会,但事实上往往并不会如你所愿,设置线程的优先级同样也是一个提示操作,具体如下:
线程的优先级不能小于1也不能大于10,如果指定的线程优先级大于线程所在group的优先级,那么指定的优先级会失效,取而代之的是group的最大优先级。如下:
//定义一个线程组
ThreadGroup group = new ThreadGroup("test");
//将线程组的优先级指定为7
group.setMaxPriority(7);
//定义一个线程,将该线程加入到group中
Thread thread = new Thread(group,"test-thread");
//企图将线程的优先级设定为10
thread.setPriority(10);
//企图未遂
System.out.println(thread.getPriority());//输出的是7
借助优先级设定某个任务的权重,这种方式是不可取的,一般定义线程的时候使用默认的优先级就好,线程默认的优先级和它的父类保持一致,一般情况下都是5.
8.线程interrupt
如下方法的调用会使得当前线程进入阻塞状态,而调用当前线程的interrupt方法,就会打断阻塞。
打断一个线程并不等于该线程的生命周期结束,仅仅是打断了当前线程的阻塞状态;一旦线程在阻塞的情况下被打断,都会抛出一个InterruptedException异常,这个异常就像一个信号通知当前线程被打断了。
(1)isInterrupted
是Thread的一个成员方法,主要判断当前线程是否被中断,该方法仅是对interrupt标识的一个判断,并不会影响标识发生任何改变。
在run方法中使用了sleep这个可中断方法,它会捕获到中断信号,并且会擦除interrupt标识。
(2)interrupted
interrupted是一个静态方法,也用于判断当前线程是否被中断,调用该方法会直接擦除掉线程的interrupt标识。如果当前线程被打断了,那么第一次调用interrupted方法会返回true,并且立即擦除了interrupt标识,第二次包括以后的调用永远都会返回false,除非此期间线程又一次地被打断。
如果一个线程设置了interrupt标识,那么接下来的可中断方法会立即中断。
9.线程join
与sleep一样也是一个可中断的方法。join某个线程A,会使当前线程B进入等待,直到线程A结束生命周期,或者到达给定的时间,那么在此期间B线程是处于BLOCKED的,而不是A线程。
join方法会使当前线程永远地等待下去,直到期间被另外的线程中断,或者join的线程执行结束。
10.补充: