廖雪峰Java11多线程编程-1线程的概念-3线程的状态

1线程的状态

<img src="https://img2018.cnblogs.com/blog/1418970/201906/1418970-20190609155854030-1712068336.png" width="500" /> 线程终止的的缘由: * run()或call()方法执行完成,线程正常结束 * 线程抛出一个未捕获的Exception或Error * 直接调用该线程的stop()方法来结束该线程——该方法容易致使死锁,一般不推荐使用java

1.1对已经死亡的线程调用start()方法使他从新启动,会引起IllegalThreadStateException

class MyThread extends Thread{
    public void run(){
        System.out.println("子线程");
    }
}
public class StartDead {
    public static void main(String[] args) throws InterruptedException{
        Thread t = new MyThread();
        t.start();
        while(t.isAlive()){
            Thread.sleep(200);
        }
        System.out.println(t.isAlive());
        t.start();
    }
}

<img src="https://img2018.cnblogs.com/blog/1418970/201906/1418970-20190609163317891-1856666325.png" width="500" />ide

2 控制线程

2.1 join线程

Thread提供了让一个线程等待另外一个线程完成的方法——join()方法。this

  • join():等待该线程执行结束,再向下执行
  • join(long mills):等待被join的线程mills毫秒,超时再也不等待
  • join(long mills, int nanos):等待最长时间为mills毫秒+nanos毫微秒,不多用
class MyThread extends Thread{
    String name;
    public MyThread(String name){
        this.name = name;
    }
    @Override
    public void run(){
        System.out.println("Hello, "+name+"!");
        try{
            Thread.sleep(2000);
        }catch (InterruptedException ex){
            ex.printStackTrace();
        }finally {
            System.out.println("Bye,"+name+"!");
        }
    }
}
public class StartDead {
    public static void main(String[] args) throws InterruptedException{
        Thread t1 = new MyThread("Bob");
        System.out.println("start");
        t1.start();
        t1.join(1000,10);
        System.out.println("end");
    }
}

<img src="https://img2018.cnblogs.com/blog/1418970/201906/1418970-20190609165330513-1373973209.png" width="500" />spa

2.2后台线程

<font color=#FF0000>Java的程序入口就是JVM启动main线程,main线程又能够启动其余线程。当全部的线程都运行结束时,JVM退出。 有一种线程是无限循环,如定时任务。若是这种线程不结束,JVM就不能退出。 问题:由谁来结束这些线程?</font> 有一种线程,他是在后台运行的,它的任务是为其余的线程提供服务,这种线程被成为“后台线程(Daemon Thread)”,又称为“守护线程”或“精灵线程”。JVM的垃圾回收线程就是典型的后台线程。 总之:线程

  • 守护线程为其余线程服务的线程
  • 全部非守护线程都执行关闭后,虚拟机退出

特征:code

  • 若是全部的前台线程都死亡,后台线程会自动死亡。
  • 不能持有资源(如打开文件等)当虚拟机退出时,守护线程没有任何机会关闭文件,会致使数据丢失。

建立守护线程:调用Thread的对象的setDaemon(true)方法能够将指定线程设置为后台线程。orm

public class DaemonThread extends Thread{
    public void run(){
        while(true){
            System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));
            try{
                Thread.sleep(1000);
            }catch (InterruptedException e){
                break;
            }

        }
    }
    public static void main(String[] args) throws InterruptedException{
        System.out.println("Main start");
        DaemonThread t = new DaemonThread();
        t.setDaemon(true);
        t.start();
        Thread.sleep(5000);
        System.out.println("Main end");
    }
}

<img src="https://img2018.cnblogs.com/blog/1418970/201906/1418970-20190609205707100-1404414409.png" width="500" />对象

package com.csj2018.lxf;

import org.junit.Ignore;
import org.junit.Test;

class DaemonThread extends Thread{
	public void run() {
		for(int i=0;i<1000;i++) {
			System.out.println(Thread.currentThread().getName()+"\t"+i);
			try {
				Thread.sleep(1000);
			}catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

public class ThreadTest2{
	@Test
	public void test() {
		Thread t = new DaemonThread();
		t.setDaemon(true);//setDaemon(true)必须在start()方法以前调用,不然会引起IllegalThreadStatsException
		t.start();
		for(int i=0;i<3;i++) {
			System.out.println(Thread.currentThread().getName()+"\t"+i);
			try {
				Thread.sleep(1000);
			}catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

<img src="https://img2018.cnblogs.com/blog/1418970/202002/1418970-20200202004852612-114306420.png" width="500" />blog

2.3线程睡眠

若是须要让正在执行的线程暂停一段时间,并进入阻塞状态,能够调用Thread类的静态方法sleep实现。当前线程调用sleep进入阻塞状态后,在其睡眠时间内,该线程不会得到执行的机会,即便系统中没有其余可执行的线程,处于sleep中的线程,依然不会执行。所以sleep经常使用于程序的执行。资源

  • static void sleep(long mills):让当前正在执行的线程暂停mills毫秒,并进入阻塞状态
  • static void sleep(long mills, int nanos):让当前正在执行的线程暂停mills毫秒+nanos毫微秒,并进入阻塞状态,第二种不多用
import java.util.Date;

public class SleepTest extends Thread {
    public static void main(String[] args) throws InterruptedException{
        for(int i=0;i<10;i++){
            System.out.println("当前时间:"+new Date());
            Thread.sleep(1000);
        }
    }
}

<img src="https://img2018.cnblogs.com/blog/1418970/201906/1418970-20190609173630860-1274522324.png" width="500" /> ### 2.4线程让步: yield yield让当前正在执行的线程暂停,但不会阻塞该线程,它只是将该线程转入就绪状态。yield()只是让当前线程暂停一下,让系统的线程调度器从新调度一次,彻底可能的状况:某个线程调用yield方法暂停后,线程调度器又将其调度出来从新执行。 当某个线程用了yield方法暂停以后,只有优先级与当前线程相同,或者优先级比当前线程更高处于就绪状态的线程才会得到执行的机会。 ```#java public class YieldTest extends Thread{ public YieldTest(String name){ super(name); } public void run(){ for(int i=0;i<10;i++){ System.out.println(Thread.currentThread().getName()+" "+i); if(i==5){ Thread.yield(); } } } public static void main(String[] args) throws InterruptedException{ YieldTest yt1 = new YieldTest("高级"); yt1.setPriority(Thread.MAX_PRIORITY); yt1.start();

YieldTest yt2 = new YieldTest("低级");
    yt2.setPriority(MIN_PRIORITY);
    yt2.start();
}

}

<img src="https://img2018.cnblogs.com/blog/1418970/201906/1418970-20190609175309658-2035292882.png" width="370" />
sleep和yield的区别:
*    sleep暂停当前线程后,会给其余线程执行机会,不会理会其余线程的优先级;但yield只会给优先级相同或更高的线程执行机会
*    sleep将线程转入阻塞状态;yield将线程转入就绪状态
*    sleep抛出InterruptedException异常;yield不会
*    sleep比yield有更好的移植性

##    3总结:
*    Java线程对象Thread的状态包括:New/Runnable/Blocked/Waiting/Timed Waiting/Terminated
*    经过对另外一个线程对象调用join()方法能够等待其执行结束
*    能够指定等待时间,超过等待时间线程仍然没有结束就再也不等待
*    对已经运行结束的线程调用join()方法会马上返回
*    守护线程是为其余线程服务的线程
*    全部非守护线程都执行完毕后,虚拟机退出
*    守护线程不能持有资源(如打开文件等)
相关文章
相关标签/搜索