java多线程学习2:sleep、join、interrupt学习

大纲在前:
1、deamon的使用补充。
2sleep
3、interrupt、isInterrupt、interrupted.
4join

deamon的使用补充
学习1中已经说了,守护线程会在所有用户线程结束后死亡同时jvm退出。
如何利用deamon的这个特点呢。
维护一个server的心跳,当心跳失效,那么业务线程就没必要存在了。此时可以将业务线程设为deamon。


sleep介绍
先来看看官网怎么说的

Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds, subject to the precision and accuracy of system timers and schedulers. The thread does not lose ownership of any monitors.

就是说调用这个方法会使当前线程暂停一段时间,同时这个线程不会丢失monitor。
sleep这个方法会抛出interrupttedexception。会捕获到中断信号。

interrupt
先看下interrupt的官方

//线程只能由自己中断
Interrupts this thread.
Unless the current thread is interrupting itself, which is always permitted, the checkAccess method of this thread is invoked, which may cause a SecurityException to be thrown.

//通过调用下面几个方法,interrupt异常会被接收到,并重置状态
If this thread is blocked in an invocation of the wait(), wait(long), or wait(long, int) methods of the Object class, or of the join(), join(long), join(long, int), sleep(long), or sleep(long, int), methods of this class, then its interrupt status will be cleared and it will receive an InterruptedException.

//nio的以后来写
If this thread is blocked in an I/O operation upon an InterruptibleChannel then the channel will be closed, the thread's interrupt status will be set, and the thread will receive a ClosedByInterruptException.

If this thread is blocked in a Selector then the thread's interrupt status will be set and it will return immediately from the selection operation, possibly with a non-zero value, just as if the selector's wakeup method were invoked.

//上述都不满足,状态值降设置
If none of the previous conditions hold then this thread's interrupt status will be set.

Interrupting a thread that is not alive need not have any effect.

总结一下:
线程的中断只有线程自己有权利。
当线程调用sleep、wait、join时,中断线程,线程会接收到interrupted异常,并清空当前状态(catch中获取的状态值时false)
非上面说的三种情况,状态值将会设置。

解释一下3:设置了状态值,线程会中断吗。当然不会。因为这只是个信号量,需要有捕获才能被中断。

所以t.interrupt并不是中断一个线程,而是发出一个信号量。由上述几种情况去捕获才能中断。

t.isinterrupt: 实例方法,返回当前状态码。
thread.interruptted:静态方法,返回当前状态码,并情况当前状态。
我猜测,在sleep、wait、join时,就用了这个静态方法进行轮询。

join
还是看官网

public final void join(long millis)
                throws InterruptedException
//等待超时时间,重源码上看,等待超时,并不影响线程的执行。
Waits at most millis milliseconds for this thread to die. A timeout of 0 means to wait forever.
//通过is。alive的while循环,来判断,当isalive。调用this。wait。所以monitor时this线程。 当线程死亡时会自动调用 this.notifyall.所以在执行线程中,建议不要调用wait、notify、notifyall。
This implementation uses a loop of this.wait calls conditioned on this.isAlive. As a thread terminates the this.notifyAll method is invoked. It is recommended that applications not use wait, notify, or notifyAll on Thread instances

紧接着看源码

public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

源码的执行流程就是判断这个调用线程是否存活,存活在调用wait堵塞当前线程。
既然有wait,那么谁来notify呢。 上面已经说了 线程执行结束会调用this.notifyall。 而这个join正好是个synchorized方法。所以monitor是调用线程对象即this。
下面是个常规的题:
一共有5个线程,前4个线程执行完成后才能执行第5个线程。
t1.start(),t2.start(),t3.start(),t4.start() t1.join() t2.join() t3.join t4.join t5.start.
那么回答一个问题。前4个线程都join到主线程中了吗。
答案不一定。如果t1.是执行时间最长的一个。那么t1.join后一直wait等待t1执行结束。那么后面的join实际上调用是isalive已经为假了。 所以只是调用不join了
因为后几个线程已经执行结束了。

我初学的时候理解有误,以为调用join就会join到主线程中,but..如上。

下面贴段代码。 这段代码中,明确说了 join该由谁interrupt。
join的中断应该由主线程中断,sleep的中断由调用线程中断。

package com.puqiuyu.thread.blog;

public class JoinDemo2 {
    public static void main(String[] args) throws InterruptedException {
        Thread a = new Thread(()->{
            System.out.println("a starting ...");
            try {
                Thread.sleep(10_000);
            } catch (InterruptedException e) {
                System.out.println("a interrupt ...");
            }
            System.out.println("a ending ...");
        });
        Thread b = new Thread(()->{
            System.out.println("b starting ...");
            try {
                Thread.sleep(5_000);
            } catch (InterruptedException e) {
                System.out.println("b interrupt  ..");
            }
            System.out.println("b ending ...");
        });
        final Thread main = Thread.currentThread();
        Thread c = new Thread(()->{
            try {
                Thread.sleep(3_000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            main.interrupt();

        });
        a.start();
        c.start();
        b.start();
        try {
            a.join();
        } catch (Exception e2) {
            System.out.println("a join ....");//intterupt时只执行这句话,说明b没有join进去
        }
        try {
            b.join();
        } catch (Exception e2) {
            System.err.println("b join ...");
        }
        System.out.println("main ending ..");
    }
}

最后,手臂疼。睡觉了。
可能里面有很多不足的,望指点,同交流。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值