高并发编程_Java线程基础 2.线程生命周期

高并发编程_Java线程基础 2.线程生命周期

1.线程生命周期图解

当new Thread是,此时线程处于新建状态,并且此时并没有真正启动一个线程。

当调用start方法启动线程时,线程由新建状态变为可运行状态。此时线程仍然没有真正的执行业务逻辑处理。

当线程之间竞争CPU资源,期中一个线程获取到CPU的使用权时,该线程变成运行状态,此时可执行真正的业务逻辑。其他为竞争到CPU使用权的线程仍然处于可运行状态。

当运行中的线程调用wait、sleep、join等方法后,线程进入等待/睡眠/阻塞状态。当线程被notify或者notifyall时,或者sleep时间已到时,线程会重新进入到可运行状态,参与CPU使用权竞争。如果线程执行完毕或者执行过程中异常退出,则线程生命周期结束,线城死亡。

2.线程API重点方法解析

2.1 setDaemon(boolean on),设置线程是否为守护线程,默认为false

public class DaemonThread {

    public static void main(String[] args) throws InterruptedException {

        Thread t = new Thread() {

            @Override
            public void run() {
                try {
                    System.out.println(Thread.currentThread().getName() + " running");
                    Thread.sleep(100000);
                    System.out.println(Thread.currentThread().getName() + " done.");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }; 
        t.start();
        t.setDaemon(true);
       


        Thread.sleep(5000);   //JDK1.7
        System.out.println(Thread.currentThread().getName());
    }
}

当设置setDaemon方法的参数为true时,当前线程变为守护线程。且setDaemon方法只能放在start方法后面,否则会抛出异常IllegalThreadStateException。当线程为守护线程时,具有一个重要的特点,该特点常用于开发中,如心跳健康监测,线程关闭等。该特点就是如果当前线程结束了,那么当前线程的子线程如果是守护线程,也会结束生命周期。不管守护线程时候还有活动,都会立刻终止。

可通过isDaemon()方法判断该线程是否是守护线程。

2.2 sleep方法

sleep有两个静态的重载方法,参数为睡眠的事件数。两个重载方法的不同点在于两个参数的方法睡眠时间可精确到微妙。

sleep表示让线程短暂睡眠指定时间,在睡眠过程让出CPU使用权给其他线程,但是并没有释放掉对象锁,并且仍然保持着监控状态。放线程睡眠时间已过时,或自动恢复到运行状态。

而对于wait方法来说,首先它不是Thread的方法,而是Object的方法。当调用wait方法时,线程进入阻塞状态。只有通过notify或者notifyall去唤醒该线程,该线程才会从新进入可运行状态,参与COU使用权竞争。

2.3 join方法

当前线程等待调用线程,知道调用线程死亡(Waits for this thread to die.)。

案例解析:

public class ThreadJoin {
	
	public static void main(String[] args) throws InterruptedException {
	    Thread t1 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				try {
					Thread.sleep(10_000);
					System.out.println("this Thread is " + Thread.currentThread().getName());
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}, "test1");
	    
	    Thread t2 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				try {
					Thread.sleep(10_000);
					System.out.println("this Thread is " + Thread.currentThread().getName());
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}, "test2");

	    t1.start();
	    t2.start();
	    t1.join();
	    t2.join();
	    System.out.println("main is done");
	}
}

//输出结果为
this Thread is test2
this Thread is test1
main is done

t1、t2线程调用join方法后,main线程需要等待t1、t2线程执行完成才能结束。如果t1、t2线程一直在执行,则main线程会一直等待下去,直到死亡。

2.4 Interrupt方法

官方文档解释如下:

如果某个线程调用wait、join、sleep方法进入等待/睡眠/阻塞状态,调用interrupt方法,可打断该线程,并且可捕获到异常InterruptedException。需要注意的是,哪个线程调用wait、join、sleep方法,该线程调用interrupt方法,才会进行打断。

public class ThreadInterrupt {

    private static final Object MONITOR = new Object();

    public static void main(String[] args) {

        Thread t = new Thread() {
            @Override
            public void run() {
                while (true) {

                }
            }
        };

        t.start();
        Thread main = Thread.currentThread();
        Thread t2 = new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                main.interrupt();
                System.out.println("interrupt");
            }
        };

        t2.start();
        try {
            t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

此案例中,调用t.join之后,main线程进入等待状态,等待其他t线程完毕。此时,只有通过main.interrupt()才会打断main线程,捕获到异常。

2.5 notify和notifyall解析

wait、notify和notifyAll方法都是定义在Object类中的方法,且都为final类型的本地方法。放在Object类中的初衷是因为考虑到synchronized的使用。因为这三个方法只能放到synchronized块中使用,否则会抛出IllegalMonitorStateException异常。使用这三个方法时,必须先获取对象的锁。 在一个加了锁的对象上,调用wait方法的目的是使得该线程让出给对象的锁资源,进入等待状态。而加锁的资源对象可能是任何类型的,对于任何类型的加锁对象,调用方法只能放到Object中。notify和notifyall同理。

notify:调用notify方法,随机唤醒等待线程中的一个线程,具体唤醒哪个线程,无法控制。如果只有一个等待状态的线程,则一定会唤醒该线程。

notifyall:唤醒所有等待中的线程。

notify、notifyall方法的具体使用后续章节在进行介绍。

此次线程相关介绍就到这里,如有描述不当地方,请指正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值