线程在一定条件下,状态会发生变化。线程变化的状态转换图如下:
1、新建状态(New):新创建了一个线程对象。
2、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
3、运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
4、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
(一)、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。
(二)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
(三)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
5、死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
控制台结果:
判断线程是否启动
控制台结果:
主线程也有可能在子线程结束之前结束。并且子线程不受影响,不会因为主线程的结束而结束。
class MyThread implements Runnable{
public void run() {
for (int i=1; i<=3; i++) {
System.out.println(Thread.currentThread().getName());
}
}
}
public class lzwCode {
public static void main(String [] args) {
MyThread my = new MyThread();
new Thread(my, "线程A").start();
new Thread(my, "线程B").start();
new Thread(my).start();
}
}
控制台结果:
说明如果我们没有指定名字的话,系统自动提供名字。
提醒一下大家:main方法其实也是一个线程。在java中所以的线程都是同时启动的,至于什么时候,哪个先执行,完全看谁先得到CPU的资源。
在java中,每次程序运行至少启动2个线程。一个是main线程,一个是垃圾收集线程。因为每当使用java命令执行一个类的时候,实际上都会启动一个JVM,每一个jVM实习在就是在操作系统中启动了一个进程。
判断线程是否启动
class MyThread implements Runnable{
public void run() {
for (int i=1; i<=3; i++) {
System.out.println(Thread.currentThread().getName());
}
}
}
public class lzwCode {
public static void main(String [] args) {
MyThread my = new MyThread();
Thread th = new Thread(my);
System.out.println("线程启动前:"+ th.isAlive()); //判断线程是否启动
th.start();
System.out.println("线程启动前:"+ th.isAlive());
}
}
控制台结果:
主线程也有可能在子线程结束之前结束。并且子线程不受影响,不会因为主线程的结束而结束。
线程的强制执行join():
package com.demo;
public class lzwCode implements Runnable{
public void run() {
for (int i=1; i<=3; i++) {
System.out.println(Thread.currentThread().getName());
}
}
public static void main(String [] args) {
lzwCode my = new lzwCode();
Thread th = new Thread(my, "线程A");
th.start();
for (int i=0; i<=10; i++) {
if (i > 5) {
try{
th.join(); //强制执行线程th
} catch(Exception e) {
e.printStackTrace();
}
}
System.out.println("main 线程执行==>"+i);
}
}
}
控制台并不是每一次都会出现如下结果:
再看一个列子:
public class lzwCode implements Runnable{
private static int a = 0;
public void run() {
for (int i=0; i<5; i++) {
a++;
}
}
public static void main(String [] args) {
Runnable my = new lzwCode();
Thread th = new Thread(my);
th.start();
System.out.println(a);
}
}
请问程序的输出结果是5吗?答案是:有可能。其实你很难遇到输出5的时候,通常情况下都不是5,几乎都是0。当然这也和机器有严重的关系。为什么呢?我的解释是当主线程main方法执行System.out.println(a);这条语句时,线程还没有真正开始运行,或许正在为它分配资源准备运行吧。因为为线程分配资源需要时间,而main方法执行完t.start()方法后继续往下执行System.out.println(a);,这个时候得到的结果是a还没有被改变的值0。怎样才能让输出结果为5!其实很简单,join()方法提供了这种功能。join()方法,它能够使调用该方法的线程在此之前执行完毕
public class lzwCode implements Runnable{
private static int a = 0;
public void run() {
for (int i=0; i<5; i++) {
a++;
}
}
public static void main(String [] args) {
Runnable my = new lzwCode();
Thread th = new Thread(my);
th.start();
try{
th.join();
}
catch (Exception e){
e.printStackTrace();
}
System.out.println(a);
}
}
这个时候,程序输入结果始终为5。
为了证明如果不使用th.join()方法,主线程main方法的System.out.println(a);语句将抢先执行,我们可以在main方法中加入一个循环,这个循环用来延长main方法执行的时间,循环次数将严重取决于机器性能。如果循环次数得当,我们也可以看到a的输出结果是5。
package com.demo;
public class lzwCode implements Runnable {
public static int a = 0;
public void run() {
for (int i = 0; i < 5; i++) {
a++;
}
}
public static void main(String[] args) throws Exception {
Runnable r = new lzwCode();
Thread th = new Thread(r);
th.start();
for (int i = 0; i < 300; i++) {
System.out.println(i);
}
System.out.println();
System.out.println(a);
}
}
这时,在我的机器上,a的输出值始终为5。
线程的休眠sleep():
public class lzwCode implements Runnable{
private static int a = 0;
public void run() {
for (int i=0; i<3; i++) {
try {
Thread.sleep(3000); //线程每隔3s执行
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+i);
}
}
public static void main(String [] args) {
Runnable my = new lzwCode();
Thread th = new Thread(my, "线程睡觉");
th.start();
}
}
【运行结果】:(结果每隔3s输出一个)
线程睡觉0
线程睡觉1
线程睡觉2
线程的中断interrupt():
public class lzwCode implements Runnable {
public void run() {
System.out.println("执行run方法");
try {
Thread.sleep(10000);
System.out.println("线程完成休眠");
} catch (Exception e) {
System.out.println("休眠被打断");
return; //返回到程序的调用处
}
System.out.println("线程正常终止");
}
public static void main(String[] args) {
lzwCode lc = new lzwCode();
Thread demo = new Thread(lc, "线程");
demo.start();
try {
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
demo.interrupt(); //2s后中断线程
}
}
【运行结果】:2秒后线程中断
执行run方法
休眠被打断