线程主要方法

2020-04-23  本文已影响0人  Ozixue
WechatIMG16221.png

线程方法,结合线程状态图一起看

  1. sleep() 与 interrupt()
    sleep(long millis): 睡眠指定时间,程序暂停运行,睡眠期间会让出CPU的执行权,去执行其它线程,同时CPU也会监视睡眠的时间,一旦睡眠时间到就会立刻执行(因为睡眠过程中仍然保留着锁,有锁只要睡眠时间到就能立刻执行)。
    sleep(): 睡眠指定时间,即让程序暂停指定时间运行,时间到了会继续执行代码,如果时间未到就要醒需要使用interrupt()来随时唤醒
    interrupt(): 唤醒正在睡眠的程序,调用interrupt()方法,会使得sleep()方法抛出InterruptedException异常,当sleep()方法抛出异常就中断了sleep的方法,从而让程序继续运行下去
    interrupt()
    有人也许认为“当调用interrupt方法时,调用对象的线程就会InterruptedException异常”, 其实这是一种误解,实际上interrupt方法只是改变了线程的“中断状态”而已,所谓中断状态是一个boolean值,表示线程是否被中断的状态。
    假设Thread-0执行了sleep、wait、join中的一个方法而停止运行,在Thread-1中调用了interrupt方法,此时线程Thread-0的确会抛出InterruptedException异常,但这其实是sleep、wait、join中的方法内部会对线程的“中断状态”进行检查,如果中断状态为true,就会抛出InterruptedException异常。假如某个线程的中断状态为true,但线程体中却没有调用或者没有判断线程中断状态的值,那么线程则不会抛出InterruptedException异常。
    isInterrupted() 检查中断状态
    若指定线程处于中断状态则返回true,若指定线程为非中断状态,则反回false, isInterrupted() 只是获取中断状态的值,并不会改变中断状态的值。
    interrupted()
    检查中断状态并清除当前线程的中断状态。如当前线程处于中断状态返回true,若当前线程处于非中断状态则返回false, 并清除中断状态(将中断状态设置为false), 只有这个方法才可以清除中断状态,Thread.interrupted的操作对象是当前线程,所以该方法并不能用于清除其它线程的中断状态。

interrupt()与interrupted()
interrupt():打断线程,将中断状态修改为true
interrupted(): 不打断线程,获取线程的中断状态,并将中断状态设置为false

public static void main(String[] args) throws Exception { 
    Thread thread0 = new Thread(()-> { 
        try { 
            System.out.println(new Date() + "\t" + Thread.currentThread().getName() + "\t太困了,让我睡10秒,中间有事叫我,zZZ。。。"); Thread.sleep(10000); 
        } catch (InterruptedException e) { 
            System.out.println(new Date() + "\t" + Thread.currentThread().getName() + "\t被叫醒了,又要继续干活了"); 
        } 
    }); 
    thread0.start();
    Thread.sleep(2000); // 这里睡眠只是为了保证先让上面的那个线程先执行
    new Thread(()-> { 
        System.out.println(new Date() + "\t" + Thread.currentThread().getName() + "\t醒醒,醒醒,别睡了,起来干活了!!!"); 
        thread0.interrupt(); // 无需获取锁就可以调用interrupt 
    }).start(); 
}
  1. wait() 与 notify()
    wait、notify和notifyAll方法是Object类的final native方法。
    所以这些方法不能被子类重写,Object类是所有类的超类,因此在程序中可以通过this或者super来调用this.wait(), super.wait()
    wait(): 导致线程进入等待阻塞状态,会一直等待直到它被其他线程通过notify()或者notifyAll唤醒。该方法只能在同步方法中调用。如果当前线程不是锁的持有者,该方法抛出一个IllegalMonitorStateException异常。wait(long timeout): 时间到了自动执行,类似于sleep(long millis)
    notify():
    该方法只能在同步方法或同步块内部调用, 随机选择一个(注意:只会通知一个)在该对象上调用wait方法的线程,解除其阻塞状态
    notifyAll():
    唤醒所有的wait对象
    注意:
  1. Object.wait()和Object.notify()和Object.notifyall()必须写在synchronized方法内部或者synchronized块内部

  2. 让哪个对象等待wait就去通知notify哪个对象,不要让A对象等待,结果却去通知B对象,要操作同一个对象
    wait():让程序暂停执行,相当于让当前,线程进入当前实例的等待队列,这个队列属于该实例对象,所以调用notify也必须使用该对象来调用,不能使用别的对象来调用。调用wait和notify必须使用同一个对象来调用。

  3. sleep() 与 wait()
    wait和sleep区别?
    sleep():可以指定线程的休眠时间,也可以不指定,到点自然醒。如果没有锁,释放线程的执行权,如果有锁,也会释放执行权但是不会释放锁对象。Thread类的静态方法
    wait():可以指定线程等待的时间也可以不指定,一定要唤醒。无论是否加锁都会释放执行权以及锁对象。在Object类里的方法

  4. wait() 与 interrupt()
    wait(): 方法的作用是释放锁,加入到等待队列,当调用interrupt()方法后,线程必须先获取到锁后,然后才抛出异常InterruptedException 。注意: 在获取锁之前是不会抛出异常的,只有在获取锁之后才会抛异常
    所有能抛出InterruptedException的方法都可以通过interrupt()来取消的
    (1)sleep在Thread类中,wait在Object类中
    (2)sleep不会释放锁,wait会释放锁
    (3)sleep使用interrupt()来唤醒,wait需要notify或者notifyAll来通知

  5. notify()和interrupt()
    从让正在wait的线程重新运行这一点来说,notify方法和intterrupt方法的作用有些类似,但仍有以下不同之处:
    (1)notify/notifyAll是java.lang.Object类的方法,唤醒的是该实例的等待队列中的线程,而不能直接指定某个具体的线程。notify/notifyAll唤醒的线程会继续执行wait的下一条语句,另外执行notify/notifyAll时线程必须要获取实例的锁
    (2)interrupte方法是java.lang.Thread类的方法,可以直接指定线程并唤醒,当被interrupt的线程处于sleep或者wait中时会抛出InterruptedException异常。执行interrupt()并不需要获取取消线程的锁。
    (3)总之notify/notifyAll和interrupt的区别在于是否能直接让某个指定的线程唤醒、执行唤醒是否需要锁、方法属于的类不同

  6. join()
    让当前线程加入父线程,加入后父线程会一直wait,直到子线程执行完毕后父线程才能执行。当我们调用某个线程的这个方法时,这个方法会挂起调用线程,直到被调用线程结束执行,调用线程才会继续执行。
    将某个线程加入到当前线程中来,一般某个线程和当前线程依赖关系比较强,必须先等待某个线程执行完毕才能执行当前线程。一般在run()方法内使用
    (1)join() 和 join(long millis, int nanos) 最后都调用了 join(long millis)。
    (2)join(long millis, int nanos)和join(long millis)方法 都是synchronized。
    (3)join() 调用了join(0),从源码可以看到join(0)不断检查当前线程是否处于Active状态。
    (4)join() 和 sleep() 一样,都可以被中断(被中断时,会抛出 InterrupptedException 异常);不同的是,join() 内部调用了wait(),会出让锁,而 sleep() 会一直保持锁。

  7. yield()
    交出CPU的执行时间,不会释放锁,让线程进入就绪状态,等待重新获取CPU执行时间,yield就像一个好人似的,当CPU轮到它了,它却说我先不急,先给其他线程执行吧, 此方法很少被使用到。

上一篇下一篇

猜你喜欢

热点阅读