线程中sleep、join、yield、wait的区别

CSDN前辈众多,本文要说全部原创,那不现实,但本文绝对走肾之文,概念知识多来自前辈博文讲解,特此感谢。

文章末尾会给出本人学习过程中翻阅的优秀博文。

正文

给出一段准备代码,相信各位一看就懂,不懂,你不懂那我不能揍你呀。

ThreadTest:

package hsy.cool.threadJY;
/**
 * 项目准备
 * @author 爱猫狗的小郝_河南济源追梦孩
 */
public class ThreadTest extends Thread{
   public ThreadTest(String name){
         super(name);
   }
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(this.getName()+"拿到了电视遥控器==========="+i);
        }
    }   
}

ThreadMain:

package hsy.cool.threadJY;
/**
 * 项目准备
 * @author 爱猫狗的小郝_河南济源追梦孩
 */
public class ThreadMain {
    public static void main(String[] args) {
        ThreadTest t1=new ThreadTest("老年人");
        ThreadTest t2=new ThreadTest("中年人");
        ThreadTest t3=new ThreadTest("小孩子");
        t1.start();
        t2.start();
        t3.start();
    }
}

相信各位一看就知道,我是在模拟老人,中年人,小孩子在一个家里为了看到自己想看的电视节目,争夺遥控器的案例(例子可能举的不是很恰当,但是,这也不重要,你说是吧,哈哈,进入正文)。

sleep()方法

为java的原生方法,需要指定等待的时间,它可以让当前正在执行的线程在指定的时间内暂停执行(睡眠),进入阻塞状态,该方法既可以让其他同优先级或者高优先级的线程得到执行的机会,也可以让低优先级的线程得到执行机会。在休眠期间该线程的资源释放,但不会释放“锁标志”,这个在synchronized代码块或方法下才有效,会锁定共享资源,如类的静态属性,对象锁等;如果没有synchronized,那共享资源同样会释放。也就是说如果有 synchronized 同步块,其他线程仍然不能访问共享数据。相信这是你看到过的最全面的sleep()方法解析。

package hsy.cool.threadJY;
/**
 * 项目准备
 * @author 爱猫狗的小郝_河南济源追梦孩
 */
public class ThreadMain {
    public static void main(String[] args) throws InterruptedException {
        ThreadTest t1=new ThreadTest("老年人");
        ThreadTest t2=new ThreadTest("中年人");
        ThreadTest t3=new ThreadTest("小孩子");
        t1.start();
        Thread.sleep(2000);
        t2.start();
        t3.start();
    }
}

当老年人看电视看累了,藏起遥控器,睡着了2秒的时间,没办法啊,全家陪着他睡,2秒过后,都醒来了,几个人继续动着自己的脑子想办法去争夺遥控器。

join()方法

执行后线程进入阻塞状态,join()方法表示 在A线程中调用B.join()方法时,A线程进入等待;join方法内部其实是使用java本地方法wait();join()方法其实就是调用Thread方法类的带参数的join方法;wait(0)相当于wait(),无限等待,直到notify,notifyall方法唤醒该线程;

package hsy.cool.threadJY;
/**
 * 项目准备
 * @author 爱猫狗的小郝_河南济源追梦孩
 */
public class ThreadMain {
    public static void main(String[] args) throws InterruptedException {
        ThreadTest t1=new ThreadTest("老年人");
        ThreadTest t2=new ThreadTest("中年人");
        ThreadTest t3=new ThreadTest("小孩子");
        t1.start();
        t1.join();
        t2.start();
        t2.join();
        t3.start();
    }
}

这个不去想具体背景了吧,因为我发现我举得例子就是一团糟,这里很明显,t1.join(),其它线程变成阻塞态,只有t1执行完释放,其它线程才能执行。

sleep()和join()方法的区别

这也说了2个方法了简单对比总结一下吧,否则显得我不走肾。

由于join的内部实现是wait(),所以使用join()方法是会释放锁的,那么其他线程就可以调用此线程的同步方法了,
而sleep(long)方法具有不是放锁的特点,因此线程会一直等待下去,直到任务完成,才会释放锁。如何,是不是很走肾,哈哈,你别打我啊!再给你补充一个细节,不准从心里口吐芬芳了!

细节:join()方法如果遇到线程的interrupt()方法有可能会出现出现异常,例如:A线程等待B线程执行任务,B线程执行到一半之后interrupt()了,此时会报 java.lang.InterruptedException异常。 此时A线程并不会终止,还是处于正常运行状态。

wait()方法和notify()、notifyAll()

wait() 方法需要和 notify() 及 notifyAll() 两个方法一起介绍,这三个方法用于协调多个线程对共享数据的存取,所以必须在 synchronized 语句块内使用,也就是说,调用 wait(),notify() 和 notifyAll() 的任务在调用这些方法前必须拥有对象的锁。
注意,它们都是 Object 类的方法,而不是 Thread 类的方法。
wait() 方法与 sleep() 方法的不同之处在于,wait() 方法会释放对象的“锁标志”。当调用某一对象的 wait() 方法后,会使当前线程暂停执行,并将当前线程放入对象等待池中,直到调用了 notify() 方法后,将从对象等待池中移出任意一个线程并放入锁标志等待池中,只有锁标志等待池中的线程可以获取锁标志,它们随时准备争夺锁的拥有权。当调用了某个对象的 notifyAll() 方法,会将对象等待池中的所有线程都移动到该对象的锁标志等待池。
除了使用 notify() 和 notifyAll() 方法,还可以使用带毫秒参数的 wait(long timeout) 方法,效果是在延迟 timeout 毫秒后,被暂停的线程将被恢复到锁标志等待池。
此外,wait(),notify() 及 notifyAll() 只能在 synchronized 语句中使用,但是如果使用的是 ReenTrantLock 实现同步,该如何达到这三个方法的效果呢?解决方法是使用 ReenTrantLock.newCondition() 获取一个 Condition 类对象,然后 Condition 的 await(),signal() 以及 signalAll() 分别对应上面的三个方法。

上代码
Wait1Test:

package hsy.cool.threadJY;
/**
 * 睡
 * @author 爱猫狗的小郝_河南济源追梦孩
 */
public class Wait1Test extends Thread{
     private Object lock;
    public Wait1Test(Object lock) {
        this.lock = lock;
    }
    @Override
    public void run() {
        try {
            synchronized (lock){
                System.out.println("开始执行哈"+System.currentTimeMillis());
                lock.wait();
                System.out.println("执行结束"+System.currentTimeMillis());
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

Wait2Test:

package hsy.cool.threadJY;
/**
 * 唤醒
 * @author 爱猫狗的小郝_河南济源追梦孩
 */
public class Wait2Test extends Thread{
    private Object lock;
    public Wait2Test(Object lock) {
        this.lock = lock;
    }
    @Override
    public void run() {
        synchronized (lock){
            System.out.println("开始唤醒"+System.currentTimeMillis());
            lock.notify();
            System.out.println("开始结束"+System.currentTimeMillis());
        }
    }
}

ThreadMain:

package hsy.cool.threadJY;
/**
 * 项目准备
 * @author 爱猫狗的小郝_河南济源追梦孩
 */
public class ThreadMain {
    public static void main(String[] args) throws InterruptedException {
        Object lock=new Object();
        Wait1Test t1=new Wait1Test(lock);
        t1.start();
        Thread.sleep(5000);
        Wait2Test t2=new Wait2Test(lock);
        t2.start();
    }
}

在这里插入图片描述
强调一点:如果t2线程没有将t1线程唤醒,t1会永远处于等待状态

细节:

wait()notify()notifyAll()都必须在synchronized中执行,否则会抛出异常

wait()notify()notifyAll()都是属于超类Object的方法

一个对象只有一个锁(对象锁和类锁还是有区别的)

wait()和sleep()区别

1.wait()可以不指定时间,sleep()必须指定时间

2.wait()会释放当前锁资源,sleep()不能够释放锁资源

3.wait()是来自Object类中,sleep()是来自Thread类

yield()方法

yield方法为Thread静态原生方法,它不能指定时间,调用yield方法会让当前线程交出CPU权限,让CPU去执行其他的线程。它跟sleep方法类似,同样不会释放锁。但是yield不能控制具体的交出CPU的时间,另外,yield方法只能让拥有相同优先级的线程有获取CPU执行时间的机会。而且,调用yield方法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只需要等待重新获取CPU执行时间,这一点是和sleep方法是不一样的。而且yield()是一种礼让,不是强制执行,调用yield方法,会建议cpu按优先级高的线程优先执行,多部分会按优先级高的线程优先执行,但也有例外,所以只能说建议。优先级从1到10,10为最高优先级,这一点和join()方法是不一样的。

其它方法

stop()
可以停止正在执行得线程,这样的方法不安全,不建议使用。他会解除线程获取的所有锁定,如果线程处于一种不连贯的状态,其他线程有可能在那种状态下检查和修改他们,很难找到问题的所在。

suspend()
容易发生死锁,调用suspend()的时候,目标线程会停止,但是却仍然有之前获取的锁定。此时,其他线程都不能有访问线程锁定的资源,除非被"挂起"的线程恢复运行。需要在Thread类中有一个标志
.若标志指出线程应该挂起,便用wait()命其进入等待状态。若标志指出线程应当恢复,则用一个notify()重新启动线程。

interrupt()
interrupt()不会中断一个正在运行的线程。这一方法实际上完成的是:在线程受到阻塞时抛出一个中断信号,线程就得以退出阻塞的状态。
.如果线程被Object.wait,Thread.join,Thread.sleep三种方法之一阻塞,那么,它将接收到一个中断异常(InterruptedException),从而提早地终结被阻塞状态。
如果线程没有被阻塞,这时调用interrupt()将不起作用。

特别感谢CSDN版块前辈们写的优秀博文,在此列出。

CSDN博主:藤原豆腐店- java多线程sleep,wait,yield方法区别
CSDN博主:漫天雪_昆仑巅 线程方法join()和sleep()区别
CSDN博主: wt520it 多线程中sleep() wait() yield() join(), interrupt(),stop(),suspend(),setPriority()用法与区别
简书博主:martin6699JAVA线程中sleep、 join、 yield、 wait区别
博客园博主:行之间线程中的sleep()、join()、yield()方法有什么区别?

发布了80 篇原创文章 · 获赞 207 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/qq_43518645/article/details/104640128