sleep、wait、yield、join方法总结

本文详细解读了Java中sleep(), wait(), yield()和join()方法的使用场景,展示了如何正确释放锁、避免死锁,以及它们在多线程协作中的关键作用。通过实例演示,探讨了生产者消费者模型和优先级反转现象。
摘要由CSDN通过智能技术生成

sleep()

sleep方法可以让线程进入Watting状态,并且不占用CPU资源,但是不释放锁,直到规定时间后再执行,休眠期间如果被中断,会抛出异常并清除中断状态;

1.演示进入synchronized方法不释放锁

public class SleepDemo implements Runnable {

    @Override
    public void run() {
        sync();
    }

    public synchronized void sync() {
        System.out.println(String.format("线程%s获取到锁,进入到sync方法", Thread.currentThread().getName()));
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(String.format("线程%s执行完sync方法", Thread.currentThread().getName()));
    }

    public static void main(String[] args) {
        SleepDemo sleepDemo = new SleepDemo();
        for(int i=0;i<20;i++) {
            new Thread(sleepDemo).start();
        }
    }
}

输出结果:

线程Thread-0获取到锁,进入到sync方法
线程Thread-0执行完sync方法
线程Thread-2获取到锁,进入到sync方法
线程Thread-2执行完sync方法
线程Thread-3获取到锁,进入到sync方法
线程Thread-3执行完sync方法
线程Thread-4获取到锁,进入到sync方法
线程Thread-4执行完sync方法
线程Thread-5获取到锁,进入到sync方法
线程Thread-5执行完sync方法
线程Thread-6获取到锁,进入到sync方法
线程Thread-6执行完sync方法
线程Thread-7获取到锁,进入到sync方法
线程Thread-7执行完sync方法
线程Thread-8获取到锁,进入到sync方法
线程Thread-8执行完sync方法
线程Thread-9获取到锁,进入到sync方法
线程Thread-9执行完sync方法
线程Thread-10获取到锁,进入到sync方法
线程Thread-10执行完sync方法
线程Thread-11获取到锁,进入到sync方法
线程Thread-11执行完sync方法
线程Thread-12获取到锁,进入到sync方法
线程Thread-12执行完sync方法
线程Thread-13获取到锁,进入到sync方法
线程Thread-13执行完sync方法
线程Thread-14获取到锁,进入到sync方法
线程Thread-14执行完sync方法
线程Thread-15获取到锁,进入到sync方法
线程Thread-15执行完sync方法
线程Thread-16获取到锁,进入到sync方法
线程Thread-16执行完sync方法
线程Thread-17获取到锁,进入到sync方法
线程Thread-17执行完sync方法
线程Thread-18获取到锁,进入到sync方法
线程Thread-18执行完sync方法
线程Thread-19获取到锁,进入到sync方法
线程Thread-19执行完sync方法
线程Thread-1获取到锁,进入到sync方法
线程Thread-1执行完sync方法

2.演示不释放Lock锁

public class SleepDemo1 implements Runnable {

    private static final Lock lock = new ReentrantLock();

    @Override
    public void run() {
        System.out.println(String.format("线程%s: 开始竞争获取lock锁", Thread.currentThread().getName()));
        lock.lock();
        System.out.println(String.format("线程%s: 竞争到lock锁", Thread.currentThread().getName()));
        try {
            System.out.println(String.format("线程%s: 开始执行自己的业务逻辑", Thread.currentThread().getName()));
            Thread.sleep(5000);
            System.out.println(String.format("线程%s: 完成业务逻辑执行", Thread.currentThread().getName()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        lock.unlock();
        System.out.println(String.format("线程%s: 释放lock锁", Thread.currentThread().getName()));
    }

    public static void main(String[] args) {
        SleepDemo1 sleepDemo1 = new SleepDemo1();
        for(int i=0;i<20;i++) {
            new Thread(sleepDemo1).start();
        }
    }
}

执行结果:

线程Thread-8: 开始竞争获取lock锁
线程Thread-8: 竞争到lock锁
线程Thread-8: 开始执行自己的业务逻辑
线程Thread-4: 开始竞争获取lock锁
线程Thread-10: 开始竞争获取lock锁
线程Thread-18: 开始竞争获取lock锁
线程Thread-5: 开始竞争获取lock锁
线程Thread-14: 开始竞争获取lock锁
线程Thread-2: 开始竞争获取lock锁
线程Thread-3: 开始竞争获取lock锁
线程Thread-12: 开始竞争获取lock锁
线程Thread-16: 开始竞争获取lock锁
线程Thread-13: 开始竞争获取lock锁
线程Thread-0: 开始竞争获取lock锁
线程Thread-6: 开始竞争获取lock锁
线程Thread-7: 开始竞争获取lock锁
线程Thread-11: 开始竞争获取lock锁
线程Thread-15: 开始竞争获取lock锁
线程Thread-19: 开始竞争获取lock锁
线程Thread-9: 开始竞争获取lock锁
线程Thread-1: 开始竞争获取lock锁
线程Thread-17: 开始竞争获取lock锁
线程Thread-8: 完成业务逻辑执行
线程Thread-4: 竞争到lock锁
线程Thread-8: 释放lock锁
线程Thread-4: 开始执行自己的业务逻辑
线程Thread-4: 完成业务逻辑执行
线程Thread-4: 释放lock锁
线程Thread-10: 竞争到lock锁
线程Thread-10: 开始执行自己的业务逻辑
线程Thread-10: 完成业务逻辑执行
线程Thread-10: 释放lock锁
线程Thread-18: 竞争到lock锁
线程Thread-18: 开始执行自己的业务逻辑
线程Thread-18: 完成业务逻辑执行
线程Thread-5: 竞争到lock锁
线程Thread-18: 释放lock锁
线程Thread-5: 开始执行自己的业务逻辑
线程Thread-5: 完成业务逻辑执行
线程Thread-14: 竞争到lock锁
线程Thread-5: 释放lock锁
线程Thread-14: 开始执行自己的业务逻辑
线程Thread-14: 完成业务逻辑执行
线程Thread-2: 竞争到lock锁
线程Thread-14: 释放lock锁
线程Thread-2: 开始执行自己的业务逻辑
线程Thread-2: 完成业务逻辑执行
线程Thread-3: 竞争到lock锁
线程Thread-2: 释放lock锁
线程Thread-3: 开始执行自己的业务逻辑
线程Thread-3: 完成业务逻辑执行
线程Thread-3: 释放lock锁
线程Thread-12: 竞争到lock锁
线程Thread-12: 开始执行自己的业务逻辑
线程Thread-12: 完成业务逻辑执行
线程Thread-12: 释放lock锁
线程Thread-16: 竞争到lock锁
线程Thread-16: 开始执行自己的业务逻辑
线程Thread-16: 完成业务逻辑执行
线程Thread-13: 竞争到lock锁
线程Thread-16: 释放lock锁
线程Thread-13: 开始执行自己的业务逻辑
线程Thread-13: 完成业务逻辑执行
线程Thread-13: 释放lock锁
线程Thread-0: 竞争到lock锁
线程Thread-0: 开始执行自己的业务逻辑
线程Thread-0: 完成业务逻辑执行
线程Thread-6: 竞争到lock锁
线程Thread-0: 释放lock锁
线程Thread-6: 开始执行自己的业务逻辑
线程Thread-6: 完成业务逻辑执行
线程Thread-7: 竞争到lock锁
线程Thread-7: 开始执行自己的业务逻辑
线程Thread-6: 释放lock锁
线程Thread-7: 完成业务逻辑执行
线程Thread-11: 竞争到lock锁
线程Thread-7: 释放lock锁
线程Thread-11: 开始执行自己的业务逻辑
线程Thread-11: 完成业务逻辑执行
线程Thread-15: 竞争到lock锁
线程Thread-11: 释放lock锁
线程Thread-15: 开始执行自己的业务逻辑
线程Thread-15: 完成业务逻辑执行
线程Thread-19: 竞争到lock锁
线程Thread-15: 释放lock锁
线程Thread-19: 开始执行自己的业务逻辑
线程Thread-19: 完成业务逻辑执行
线程Thread-19: 释放lock锁
线程Thread-9: 竞争到lock锁
线程Thread-9: 开始执行自己的业务逻辑
线程Thread-9: 完成业务逻辑执行
线程Thread-9: 释放lock锁
线程Thread-1: 竞争到lock锁
线程Thread-1: 开始执行自己的业务逻辑
线程Thread-1: 完成业务逻辑执行
线程Thread-17: 竞争到lock锁
线程Thread-1: 释放lock锁
线程Thread-17: 开始执行自己的业务逻辑
线程Thread-17: 完成业务逻辑执行
线程Thread-17: 释放lock锁

3.演示执行sleep方法过后被中断抛出异常

public class SleepDemo2 implements Runnable {

    @Override
    public void run() {
        try {
            Thread.sleep(60000);
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println(String.format("线程%s: 线程执行sleep方法过后,处于wating状态。被中断时,会被唤醒,并抛出该异常", Thread.currentThread().getName()));
        }
    }

    public static void main(String[] args) {
        SleepDemo2 sleepDemo2 = new SleepDemo2();
        Thread thread = new Thread(sleepDemo2);
        thread.start();
        try {
            Thread.sleep(3000);
            System.out.println(String.format("主线程暂停3s中过后,开始中断thread线程"));
            thread.interrupt();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

输出结果为:

主线程暂停3s中过后,开始中断thread线程
线程Thread-0: 线程执行sleep方法过后,处于wating状态。被中断时,会被唤醒,并抛出该异常
java.lang.InterruptedException: sleep interrupted
	at java.base/java.lang.Thread.sleep(Native Method)
	at SleepDemo2.run(SleepDemo2.java:6)
	at java.base/java.lang.Thread.run(Thread.java:834)

wait()

wait()的作用是让当前线程进入等待状态。同时,wait()也会让当前线程释放调用该方法的对象锁。“直到其他线程调用此对象的 notify() 方法、 notifyAll() 方法或者超过指定的时间量”,当前线程被唤醒(进入“就绪状态”)

注意:

  1. wait()一定要使用sycronized进行同步,否则会报java.lang.IllegalMonitorStateException异常。这是因为wait方法会释放当前对象的锁,而此时因为没有用sycronized同步,就没有锁,就会报异常。
  2. 锁指的是sycronized修饰的方法、对象、代码块,实例变量。
  3. 因为wait()释放了锁,故其他线程可以执行本来由sycronized修饰的内容。

1.演示释放synchronized修饰的非静态方法锁

public class WaitDemo implements Runnable {

    @Override
    public void run() {
        sync();
    }
    //synchronized修饰的方法,代表当前锁对象为WaitDemo的对象实例
    public synchronized void sync() {
        System.out.println(String.format("%s线程%s: 线程获取到锁,进入到sync方法", LocalDateTime.now().format(DateTimeFormatter.ISO_TIME),
                Thread.currentThread().getName()));
        try {
            System.out.println(String.format("%s线程%s: 调用wait方法,进入等待状态", LocalDateTime.now().format(DateTimeFormatter.ISO_TIME),
                    Thread.currentThread().getName()));
            //用this调用wait方法,就会释放synchronized的WaitDemo对象实例锁
            this.wait(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(String.format("%s线程%s: 线程执行完sync方法", LocalDateTime.now().format(DateTimeFormatter.ISO_TIME),
                Thread.currentThread().getName()));
    }

    public static void main(String[] args) {
        WaitDemo waitDemo = new WaitDemo();
        for(int i=0;i<20;i++) {
            new Thread(waitDemo).start();
        }
    }
}

输出结果:

14:32:44.8510709线程Thread-0: 线程获取到锁,进入到sync方法
14:32:44.8829849线程Thread-0: 调用wait方法,进入等待状态
14:32:44.8839831线程Thread-19: 线程获取到锁,进入到sync方法
14:32:44.8839831线程Thread-19: 调用wait方法,进入等待状态
14:32:44.8849801线程Thread-18: 线程获取到锁,进入到sync方法
14:32:44.8849801线程Thread-18: 调用wait方法,进入等待状态
14:32:44.8849801线程Thread-17: 线程获取到锁,进入到sync方法
14:32:44.8849801线程Thread-17: 调用wait方法,进入等待状态
14:32:44.8859785线程Thread-16: 线程获取到锁,进入到sync方法
14:32:44.8859785线程Thread-16: 调用wait方法,进入等待状态
14:32:44.8859785线程Thread-15: 线程获取到锁,进入到sync方法
14:32:44.8859785线程Thread-15: 调用wait方法,进入等待状态
14:32:44.8869749线程Thread-14: 线程获取到锁,进入到sync方法
14:32:44.8869749线程Thread-14: 调用wait方法,进入等待状态
14:32:44.8869749线程Thread-13: 线程获取到锁,进入到sync方法
14:32:44.8879714线程Thread-13: 调用wait方法,进入等待状态
14:32:44.8879714线程Thread-12: 线程获取到锁,进入到sync方法
14:32:44.8879714线程Thread-12: 调用wait方法,进入等待状态
14:32:44.8879714线程Thread-11: 线程获取到锁,进入到sync方法
14:32:44.8889701线程Thread-11: 调用wait方法,进入等待状态
14:32:44.8889701线程Thread-10: 线程获取到锁,进入到sync方法
14:32:44.8889701线程Thread-10: 调用wait方法,进入等待状态
14:32:44.8889701线程Thread-9: 线程获取到锁,进入到sync方法
14:32:44.8889701线程Thread-9: 调用wait方法,进入等待状态
14:32:44.889966线程Thread-3: 线程获取到锁,进入到sync方法
14:32:44.889966线程Thread-3: 调用wait方法,进入等待状态
14:32:44.889966线程Thread-2: 线程获取到锁,进入到sync方法
14:32:44.889966线程Thread-2: 调用wait方法,进入等待状态
14:32:44.8909638线程Thread-4: 线程获取到锁,进入到sync方法
14:32:44.8909638线程Thread-4: 调用wait方法,进入等待状态
14:32:44.8909638线程Thread-5: 线程获取到锁,进入到sync方法
14:32:44.8909638线程Thread-5: 调用wait方法,进入等待状态
14:32:44.8909638线程Thread-7: 线程获取到锁,进入到sync方法
14:32:44.8919609线程Thread-7: 调用wait方法,进入等待状态
14:32:44.8919609线程Thread-6: 线程获取到锁,进入到sync方法
14:32:44.8919609线程Thread-6: 调用wait方法,进入等待状态
14:32:44.8919609线程Thread-8: 线程获取到锁,进入到sync方法
14:32:44.8919609线程Thread-8: 调用wait方法,进入等待状态
14:32:44.8929592线程Thread-1: 线程获取到锁,进入到sync方法
14:32:44.8929592线程Thread-1: 调用wait方法,进入等待状态
14:32:49.8855091线程Thread-0: 线程执行完sync方法
14:32:49.8865149线程Thread-18: 线程执行完sync方法
14:32:49.8865149线程Thread-19: 线程执行完sync方法
14:32:49.9015961线程Thread-6: 线程执行完sync方法
14:32:49.9026036线程Thread-16: 线程执行完sync方法
14:32:49.9026036线程Thread-17: 线程执行完sync方法
14:32:49.9036058线程Thread-14: 线程执行完sync方法
14:32:49.9044266线程Thread-15: 线程执行完sync方法
14:32:49.9052275线程Thread-13: 线程执行完sync方法
14:32:49.9062683线程Thread-11: 线程执行完sync方法
14:32:49.9071542线程Thread-12: 线程执行完sync方法
14:32:49.9081587线程Thread-10: 线程执行完sync方法
14:32:49.9087421线程Thread-3: 线程执行完sync方法
14:32:49.9097298线程Thread-9: 线程执行完sync方法
14:32:49.9107345线程Thread-4: 线程执行完sync方法
14:32:49.9117304线程Thread-2: 线程执行完sync方法
14:32:49.912115线程Thread-5: 线程执行完sync方法
14:32:49.9130378线程Thread-7: 线程执行完sync方法
14:32:49.9140422线程Thread-8: 线程执行完sync方法
14:32:49.9147798线程Thread-1: 线程执行完sync方法

2.演示释放synchronized的实例变量对象锁


public class WaitDemo1 implements Runnable {

    private String value = "lock";

    @Override
    public void run() {
        System.out.println(String.format("%s线程%s:线程竞争获取value实例锁", LocalDateTime.now().format(DateTimeFormatter.ISO_TIME), Thread.currentThread().getName()));
        synchronized (value) {
            System.out.println(String.format("%s线程%s:线程获取到value对象锁",  LocalDateTime.now().format(DateTimeFormatter.ISO_TIME), Thread.currentThread().getName()));
            try {
                System.out.println(String.format("%s线程%s:线程执行wait方法,进入等待状态,并释放当前对象锁", LocalDateTime.now().format(DateTimeFormatter.ISO_TIME), Thread.currentThread().getName()));
                //this.wait(5000);  //该行代码在执行到时候会报错,因为synchronized代码块的对象锁为value,因此调用this.wait方法没发释放this对象锁
                value.wait(5000); //由于synchronized代码块的对象锁为value,因此只能使用value对象来进行等待
                System.out.println(String.format("%s线程%s:线程执行wait方法后被唤醒,进入就绪状态,等待再次获取value对象锁", LocalDateTime.now().format(DateTimeFormatter.ISO_TIME), Thread.currentThread().getName()));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(String.format("%s线程%s:线程执行完synchronized同步代码块", LocalDateTime.now().format(DateTimeFormatter.ISO_TIME), Thread.currentThread().getName()));
    }

    public static void main(String[] args) {
        WaitDemo1 waitDemo1 = new WaitDemo1();
        for(int i=0;i<10;i++) {
            new Thread(waitDemo1).start();
        }
    }
}

输出结果为:

17:06:07.537线程Thread-0:线程竞争获取value实例锁
17:06:07.537线程Thread-6:线程竞争获取value实例锁
17:06:07.537线程Thread-9:线程竞争获取value实例锁
17:06:07.537线程Thread-3:线程竞争获取value实例锁
17:06:07.537线程Thread-7:线程竞争获取value实例锁
17:06:07.537线程Thread-2:线程竞争获取value实例锁
17:06:07.537线程Thread-4:线程竞争获取value实例锁
17:06:07.537线程Thread-8:线程竞争获取value实例锁
17:06:07.537线程Thread-1:线程竞争获取value实例锁
17:06:07.537线程Thread-5:线程竞争获取value实例锁
17:06:07.613线程Thread-0:线程获取到value对象锁
17:06:07.616线程Thread-0:线程执行wait方法,进入等待状态,并释放当前对象锁
17:06:07.616线程Thread-5:线程获取到value对象锁
17:06:07.617线程Thread-5:线程执行wait方法,进入等待状态,并释放当前对象锁
17:06:07.617线程Thread-1:线程获取到value对象锁
17:06:07.618线程Thread-1:线程执行wait方法,进入等待状态,并释放当前对象锁
17:06:07.618线程Thread-8:线程获取到value对象锁
17:06:07.618线程Thread-8:线程执行wait方法,进入等待状态,并释放当前对象锁
17:06:07.618线程Thread-4:线程获取到value对象锁
17:06:07.618线程Thread-4:线程执行wait方法,进入等待状态,并释放当前对象锁
17:06:07.619线程Thread-2:线程获取到value对象锁
17:06:07.619线程Thread-2:线程执行wait方法,进入等待状态,并释放当前对象锁
17:06:07.619线程Thread-7:线程获取到value对象锁
17:06:07.619线程Thread-7:线程执行wait方法,进入等待状态,并释放当前对象锁
17:06:07.62线程Thread-3:线程获取到value对象锁
17:06:07.62线程Thread-3:线程执行wait方法,进入等待状态,并释放当前对象锁
17:06:07.62线程Thread-9:线程获取到value对象锁
17:06:07.62线程Thread-9:线程执行wait方法,进入等待状态,并释放当前对象锁
17:06:07.621线程Thread-6:线程获取到value对象锁
17:06:07.621线程Thread-6:线程执行wait方法,进入等待状态,并释放当前对象锁
17:06:12.622线程Thread-0:线程执行wait方法后被唤醒,进入就绪状态,等待再次获取value对象锁
17:06:12.628线程Thread-0:线程执行完synchronized同步代码块
17:06:12.629线程Thread-3:线程执行wait方法后被唤醒,进入就绪状态,等待再次获取value对象锁
17:06:12.629线程Thread-3:线程执行完synchronized同步代码块
17:06:12.63线程Thread-7:线程执行wait方法后被唤醒,进入就绪状态,等待再次获取value对象锁
17:06:12.631线程Thread-4:线程执行wait方法后被唤醒,进入就绪状态,等待再次获取value对象锁
17:06:12.631线程Thread-7:线程执行完synchronized同步代码块
17:06:12.633线程Thread-2:线程执行wait方法后被唤醒,进入就绪状态,等待再次获取value对象锁
17:06:12.633线程Thread-4:线程执行完synchronized同步代码块
17:06:12.633线程Thread-2:线程执行完synchronized同步代码块
17:06:12.634线程Thread-8:线程执行wait方法后被唤醒,进入就绪状态,等待再次获取value对象锁
17:06:12.634线程Thread-8:线程执行完synchronized同步代码块
17:06:12.634线程Thread-5:线程执行wait方法后被唤醒,进入就绪状态,等待再次获取value对象锁
17:06:12.637线程Thread-6:线程执行wait方法后被唤醒,进入就绪状态,等待再次获取value对象锁
17:06:12.637线程Thread-5:线程执行完synchronized同步代码块
17:06:12.64线程Thread-6:线程执行完synchronized同步代码块
17:06:12.64线程Thread-9:线程执行wait方法后被唤醒,进入就绪状态,等待再次获取value对象锁
17:06:12.641线程Thread-9:线程执行完synchronized同步代码块
17:06:12.641线程Thread-1:线程执行wait方法后被唤醒,进入就绪状态,等待再次获取value对象锁
17:06:12.641线程Thread-1:线程执行完synchronized同步代码块

上诉代码如果执行this.wait(5000)进行等待,程序会报java.lang.IllegalMonitorStateException异常,因为this对象执行wait方法后,会释放this对象锁,由于当前同步代码块的对象锁为value,所以不存在this对象锁,就会报错。

3.对wait方法和notify/notifyAll方法简单到阐述

对象锁的本质,重量级锁模式时对象头是一个指向互斥量的指针,实际上互斥量就是一个监视器锁(ObjectMonitor)的数据结构,此时对象的hashCode、分代年龄等信息都会保存到对应的ObjectMonitor中,ObjectMonitor还有一些属性如recursion记录本锁被重入的次数,EntrySet记录想获取本锁的线程集合,WaitSet记录等待本锁的线程,TheOwner记录拥有本锁的线程对象。如下:

image

几个线程一起竞争对象的锁(EntrySet),只有一个能成功(acquire),成功的线程记录在The Owner中。调用wait、notify运行流程如下:

  • (1) 现有一个对象o,锁正在被线程t1持有,调用wait()方法后,线程 t1 将会被"晾到" (实际上仅仅是记录到) WaitSet 结构中。

  • (2)然后将会有另一个线程 t2 获取到锁,TheOwner记录的变成了 t2 线程。

  • (3)t2 线程不需要o的锁时,调用o.notify()/o.notifyAll()方法,对象o就会告诉 WaitSet结构中记录的线程们:你们又可以来竞争我啦,我的锁现在没被人持有。

因此,就可以知道,wait方法和notify/notifyAll方法需要放在同步代码块中,这样就可以获取到当前对象到同步锁,在执行后,就可以放弃放弃当前对象锁到持有,让其他线程能够进行对对象锁的竞争。

4.wait和notify方法案例(生产者和消费者)

public class WaitDemo2 {

    static class Box {

        private int size;

        private int num = 0;

        private String[] list;

        public Box(int size) {
            this.size = size;
            list = new String[size];
        }

        //向集合中存放数据
        synchronized void put(String str) {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            while(size <= num+1) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            list[num] = str;
            System.out.println(String.format("生产者:%s生产的数据为%s", Thread.currentThread().getName(), str));
            num ++;
            this.notify();
        }

        //向结合中取出数据
        synchronized void toke() {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            while(num == 0) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            String result = list[num-1];
            System.out.println(String.format("消费者:%s消费的数据为%s", Thread.currentThread().getName() ,result));
            num --;
            this.notify();
        }
    }

    static class Provider implements Runnable{

        private Box box;

        public Provider(Box box) {
            this.box = box;
        }

        @Override
        public void run() {
            while (true) {
                box.put(UUID.randomUUID().toString());
            }
        }
    }

    static class Consumer implements Runnable {

        private Box box;

        public Consumer(Box box) {
            this.box = box;
        }

        @Override
        public void run() {
            while (true) {
                box.toke();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Box box = new Box(10);
        new Thread(new Provider(box)).start();
        new Thread(new Consumer(box)).start();
    }

}

yield()

yield()是让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程获得运行机会。因此,使用yield()的目的是让相同优先级的线程之间能适当的轮转执行。但是,实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。yield()从未导致线程转到等待/睡眠/阻塞状态。

public class YieldDemo {

    static class Producer implements Runnable {

        @Override
        public void run() {
            for(int i=0;i<10;i++) {
                Thread.yield();
                System.out.println(String.format("%s线程%s: 我是Producer, 输出%d", LocalDateTime.now()
                        .format(DateTimeFormatter.ISO_TIME), Thread.currentThread().getName(), i));
            }
        }
    }

    static class Consumer implements Runnable {

        @Override
        public void run() {
            for(int i=0;i<10;i++) {
                System.out.println(String.format("%s线程%s: 我是Consumer, 输出%d", LocalDateTime.now()
                        .format(DateTimeFormatter.ISO_TIME), Thread.currentThread().getName(), i));
            }
        }
    }

    public static void main(String[] args) {
        Thread producer = new Thread(new Producer());
        Thread consumer = new Thread(new Consumer());

        producer.setPriority(Thread.MAX_PRIORITY);
        consumer.setPriority(Thread.MIN_PRIORITY);

        producer.start();
        consumer.start();
    }
}

输出结果:

14:57:00.194线程Thread-1: 我是Consumer, 输出0
14:57:00.193线程Thread-0: 我是Producer, 输出0
14:57:00.235线程Thread-0: 我是Producer, 输出1
14:57:00.235线程Thread-1: 我是Consumer, 输出1
14:57:00.235线程Thread-0: 我是Producer, 输出2
14:57:00.235线程Thread-1: 我是Consumer, 输出2
14:57:00.236线程Thread-1: 我是Consumer, 输出3
14:57:00.235线程Thread-0: 我是Producer, 输出3
14:57:00.236线程Thread-1: 我是Consumer, 输出4
14:57:00.236线程Thread-0: 我是Producer, 输出4
14:57:00.236线程Thread-1: 我是Consumer, 输出5
14:57:00.237线程Thread-1: 我是Consumer, 输出6
14:57:00.237线程Thread-1: 我是Consumer, 输出7
14:57:00.237线程Thread-0: 我是Producer, 输出5
14:57:00.238线程Thread-0: 我是Producer, 输出6
14:57:00.237线程Thread-1: 我是Consumer, 输出8
14:57:00.238线程Thread-1: 我是Consumer, 输出9
14:57:00.238线程Thread-0: 我是Producer, 输出7
14:57:00.24线程Thread-0: 我是Producer, 输出8
14:57:00.24线程Thread-0: 我是Producer, 输出9

join()

join()方法可以使得一个线程在另一个线程结束后再执行。如果join()方法在一个线程实例上调用,当前运行着的线程将阻塞直到这个线程实例完成了执行。

注意:调用线程实例应该调用了start方法过后,再调用join方法才能达到等待的效果

public class JoinDemo implements Runnable {

    @Override
    public void run() {
        try {
            System.out.println(String.format("%s线程%s:线程准备睡眠5s", LocalDateTime.now().format(DateTimeFormatter.ISO_TIME), Thread.currentThread().getName()));
            Thread.sleep(5000);
            System.out.println(String.format("%s线程%s:线程睡眠5s结束", LocalDateTime.now().format(DateTimeFormatter.ISO_TIME), Thread.currentThread().getName()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        System.out.println(String.format("%s线程%s:线程开始执行main方法", LocalDateTime.now().format(DateTimeFormatter.ISO_TIME), Thread.currentThread().getName()));
        Thread thread = new Thread(new JoinDemo());
        thread.start();
        try {
            thread.join(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(String.format("%s线程%s:线程执行main方法结束", LocalDateTime.now().format(DateTimeFormatter.ISO_TIME), Thread.currentThread().getName()));

    }
}

输出结果为:

15:13:21.294线程main:线程开始执行main方法
15:13:21.338线程Thread-0:线程准备睡眠5s
15:13:26.346线程Thread-0:线程睡眠5s结束
15:13:26.345线程main:线程执行main方法结束
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值