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() 方法或者超过指定的时间量”,当前线程被唤醒(进入“就绪状态”)
注意:
- wait()一定要使用sycronized进行同步,否则会报
java.lang.IllegalMonitorStateException
异常。这是因为wait方法会释放当前对象的锁,而此时因为没有用sycronized同步,就没有锁,就会报异常。 - 锁指的是sycronized修饰的方法、对象、代码块,实例变量。
- 因为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记录拥有本锁的线程对象。如下:
几个线程一起竞争对象的锁(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方法结束