notify、join、yield的方法说明

wait方法:在执行wait方法后,当前线程立即释放锁,wait下面的代码不会再执行了。

sleep方法:而线程sleep之后依然持有锁,我睡了但是你也别想运行。注意,如果当前线程获得了一把同步锁,则 sleep方法阻塞期间,是不会释放锁的。

yield方法:使当前线程从执行状态(运行状态)变为可执行态(就绪状态)。cpu会从众多的可执行态里随机选择,也就是说,当前也就是刚刚的那个线程还是有可能会被再次执行到的。也就是从Running变为Ready,一直在Runnable里面。

join:在B线程里面写threadA.join( ),B挂起,让A运行,看起来B很礼貌让A运行了,但其实B很虚伪,让别人运行又不释放锁。

notify:在执行notify方法后,当前线程不会马上释放该对象锁,呈wait状态的线程也并不能马上获取该对象锁,要等到执行notify方法的线程将程序执行完,也就是退出synchronized代码块后,当前线程才会释放锁,而呈wait状态所在的线程才可以获取该对象锁。

1.wait、notify和notifyAll

首先,它们都是Object类中的方法。需要配合 Synchronized关键字来使用。

调用线程的wait方法会使当前线程等待,直到其它线程调用此对象的notify/notifyAll方法。 如果,当前对象锁有N个线程在等待,则notify方法会随机唤醒其中一个线程,而notifyAll会唤醒对象锁中所有的线程。需要注意,唤醒时,不会立马释放锁,只有当前线程执行完之后,才会把锁释放。

另外,wait方法和sleep方法不同之处,在于sleep方法不会释放锁,而wait方法会释放锁。wait、notify的使用如我之前写过的一篇里
https://www.jianshu.com/p/85e550555f74

2. join

当线程调用另外一个线程的join方法时,当前线程就会进入阻塞状态。直到另外一个线程执行完毕,当前线程才会由阻塞状态转为就绪状态。

当被问到,怎么才能保证t1,t2,t3线程按顺序执行呢。(因为,我们知道,正常情况下,调用start方法之后,是不能控制线程的执行顺序的)
其实,是非常简单的,用join方法就可以轻松实现:

public class TestJoin {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new MultiT("a"));
        Thread t2 = new Thread(new MultiT("b"));
        Thread t3 = new Thread(new MultiT("c"));
        
        t1.start();
        t1.join();

        t2.start();
        t2.join();

        t3.start();
        t3.join();
    }

}

class MultiT implements Runnable{
    private String s;
    private int i;

    public MultiT(String s){
        this.s = s;
    }

    @Override
    public void run() {
        while(i<10){
            System.out.println(s+"===="+i++);
        }
    }
}

最终,我们会看到,线程会按照t1,t2,t3顺序执行。因为,主线程main总会等调用join方法的那个线程执行完之后,才会往下执行。

3. yield

Thread.yield 方法会使当前线程放弃CPU时间片,把执行机会让给相同或更高优先级的线程(yield英文意思就是屈服,放弃的意思嘛,可以理解为当前线程暂时屈服于别人了)。

注意,此时当前线程不会阻塞,只是进入了就绪状态,随时可以再次获得CPU时间片,从而进入运行状态。也就是说,其实yield方法,并不能保证,其它相同或更高优先级的线程一定会获得执行权,也有可能,再次被当前线程拿到执行权。

yield方法和sleep方法一样,也是不释放锁资源的。可以通过代码来验证这一点:

public class TestYield {
    public static void main(String[] args) {
        YieldThread yieldThread = new YieldThread();
        for (int i = 0; i < 10; i++) {
            Thread t = new Thread(yieldThread);
            t.start();
        }
    }
}

class YieldThread implements Runnable {

    private int count = 0;

    @Override
    public synchronized void run() {
        for (int i = 0; i < 10; i++) {
            count ++;
            if(count == 1){
                Thread.yield();
                System.out.println("线程:"+Thread.currentThread().getName() + "让步");
            }
            System.out.println("线程:"+Thread.currentThread().getName() + ",count:"+count);
        }
    }
}

yield一般用于不存在锁竞争的多线程环境中。如果当前线程执行的任务时间可能比较长,就可以选择用yield方法,暂时让出CPU执行权。让其它线程也有机会执行任务,而不至于让CPU资源一直消耗在当前线程。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容