AI智能
改变未来

多线程wait/notify与sleep/yield/join的通俗理解

  1. 面向对象设计来源于现实世界,软件中的设计均有现实的场景对应,按照人类世界来理解普通的对象与Thread线程,普通对象拥有内存资源,Thread线程拥有cpu时间片即计算资源;在人类世界中,普通对象可以看成是老板,Thread线程可以看成是员工,老板拥有资源,员工拥有时间和计算技能。wait/notify是Object的方法,即老板的方法,synchronized 指的是Thread线程对Object资源的排斥性占有,但资源是老板的,老板说了算,说给谁就给谁,所以wait方法调用的时候是释放锁的。
    以下为示例代码:
package org.loyuru.multi.thread.composite;/*** 公司老板让采购部职员张三采购电脑放到仓库中,让IT部李四从仓库中取电脑里安装操作系统* 因为wait/notify是老板的方法,老板能控制张三和李四,让他们协作工作* 老板让他们等待的时候,会把仓库的锁收回来,给另外一个人* @author Teddy Lee* @date 2020年3月16日*/public class Company {private int computer = 0;public synchronized void purchaseComputer() {if (this.computer > 4) {try {System.out.println(Thread.currentThread().getName()+\":老四,仓库已经满了,先不采购新电脑了,等你安装完了再采购!\");wait();} catch (InterruptedException e) {e.printStackTrace();}}computer++;System.out.println(Thread.currentThread().getName()+\":采购新电脑来了,放到了仓库里,老四你快来安装操作系统!\");notify();}public synchronized int installSystem() {if (this.computer == 0) {try {System.out.printf(Thread.currentThread().getName()+\":老三,仓库电脑都安装完成操作系统了,我等着你采购!\");wait();} catch (InterruptedException e) {e.printStackTrace();}}computer--;System.out.println(Thread.currentThread().getName()+\":我安装了一个操作系统,仓库有空余位置了,老三你可以采购了!\");notify();return computer;}public static void main(String[] args) {Company boss = new Company();Thread zhangsan = new Thread(() -> {for (int i = 0; i < 10; i++) {boss.purchaseComputer();}});zhangsan.setName(\"张三\");Thread lisi = new Thread(() -> {for (int i = 0; i < 10; i++) {boss.installSystem();}});lisi.setName(\"李四\");zhangsan.start();lisi.start();}}

执行结果:
张三:采购新电脑来了,放到了仓库里,老四你快来安装操作系统!
张三:采购新电脑来了,放到了仓库里,老四你快来安装操作系统!
张三:采购新电脑来了,放到了仓库里,老四你快来安装操作系统!
张三:采购新电脑来了,放到了仓库里,老四你快来安装操作系统!
张三:采购新电脑来了,放到了仓库里,老四你快来安装操作系统!
张三:老四,仓库已经满了,先不采购新电脑了,等你安装完了再采购!
李四:我安装了一个操作系统,仓库有空余位置了,老三你可以采购了!
李四:我安装了一个操作系统,仓库有空余位置了,老三你可以采购了!
李四:我安装了一个操作系统,仓库有空余位置了,老三你可以采购了!
李四:我安装了一个操作系统,仓库有空余位置了,老三你可以采购了!
李四:我安装了一个操作系统,仓库有空余位置了,老三你可以采购了!
李四:老三,仓库电脑都安装完成操作系统了,我等着你采购!张三:采购新电脑来了,放到了仓库里,老四你快来安装操作系统!
张三:采购新电脑来了,放到了仓库里,老四你快来安装操作系统!
张三:采购新电脑来了,放到了仓库里,老四你快来安装操作系统!
张三:采购新电脑来了,放到了仓库里,老四你快来安装操作系统!
张三:采购新电脑来了,放到了仓库里,老四你快来安装操作系统!
李四:我安装了一个操作系统,仓库有空余位置了,老三你可以采购了!
李四:我安装了一个操作系统,仓库有空余位置了,老三你可以采购了!
李四:我安装了一个操作系统,仓库有空余位置了,老三你可以采购了!
李四:我安装了一个操作系统,仓库有空余位置了,老三你可以采购了!
李四:我安装了一个操作系统,仓库有空余位置了,老三你可以采购了!

  1. sleep是Tread类方法,在现实生活中可以理解为员工工作累了,想偷懒休息一会,但员工上班时间不能离开公司啊,所以不会释放锁。
    以下为示例代码:
package org.loyuru.multi.thread.composite;/*** 公司老板让采购部职员张三采购电脑放到仓库中,让IT部李四从仓库中取电脑里安装操作系统* sleep是员工的方法,员工偷懒睡觉,但是不敢离开公司,即不敢释放锁** @author Teddy Lee* @date 2020年3月16日*/public class Company2 {private int computer = 0;public void purchaseComputer() {computer++;System.out.println(Thread.currentThread().getName() + \":采购新电脑来了!\");}public int installSystem() {computer--;System.out.println(Thread.currentThread().getName() + \":我安装了一个操作系统!\");return computer;}public static void main(String[] args) {Company2 boss = new Company2();Thread zhangsan = new Thread(() -> {synchronized (boss) {for (int i = 0; i < 10; i++) {boss.purchaseComputer();try {System.out.println(Thread.currentThread().getName() + \":我累了,睡会觉!\");Thread.sleep(100l);} catch (InterruptedException e) {e.printStackTrace();}}}});zhangsan.setName(\"张三\");Thread lisi = new Thread(() -> {synchronized (boss) {for (int i = 0; i < 10; i++) {boss.installSystem();try {System.out.println(Thread.currentThread().getName() + \":我累了,睡会觉!\");Thread.sleep(100l);} catch (InterruptedException e) {e.printStackTrace();}}}});lisi.setName(\"李四\");zhangsan.start();lisi.start();}}

执行结果:
张三:采购新电脑来了!
张三:我累了,睡会觉!
张三:采购新电脑来了!
张三:我累了,睡会觉!
张三:采购新电脑来了!
张三:我累了,睡会觉!
张三:采购新电脑来了!
张三:我累了,睡会觉!
张三:采购新电脑来了!
张三:我累了,睡会觉!
张三:采购新电脑来了!
张三:我累了,睡会觉!
张三:采购新电脑来了!
张三:我累了,睡会觉!
张三:采购新电脑来了!
张三:我累了,睡会觉!
张三:采购新电脑来了!
张三:我累了,睡会觉!
张三:采购新电脑来了!
张三:我累了,睡会觉!
李四:我安装了一个操作系统!
李四:我累了,睡会觉!
李四:我安装了一个操作系统!
李四:我累了,睡会觉!
李四:我安装了一个操作系统!
李四:我累了,睡会觉!
李四:我安装了一个操作系统!
李四:我累了,睡会觉!
李四:我安装了一个操作系统!
李四:我累了,睡会觉!
李四:我安装了一个操作系统!
李四:我累了,睡会觉!
李四:我安装了一个操作系统!
李四:我累了,睡会觉!
李四:我安装了一个操作系统!
李四:我累了,睡会觉!
李四:我安装了一个操作系统!
李四:我累了,睡会觉!
李四:我安装了一个操作系统!
李四:我累了,睡会觉!

  1. yield方法是Thread类方法,调用后可能出让cpu时间片,但不会释放锁,不稳定,因为调用后不一定什么时候出让时间片。现实中,员工正在敲代码,然后感觉有点累,想着要不要休息会,休息的过程中,行政部女秘书会来打扫办公桌。
    以下为示例代码:
package org.loyuru.multi.thread.composite;/*** 张三和李四都是程序员,休息的时候,可以叫行政女秘书来打扫办公桌** @author Teddy Lee* @date 2020年3月16日*/public class Company3 {public void code() {System.out.println(Thread.currentThread().getName() + \":编码中!\");}public static void main(String[] args) {Company3 company = new Company3();Thread zhangsan = new Thread(() -> {synchronized (company) {for (int i = 0; i < 5; i++) {company.code();System.out.println(Thread.currentThread().getName() + \":我要不要休息一会?\");Thread.yield();}}});zhangsan.setName(\"张三\");Thread lisi = new Thread(() -> {synchronized (company) {for (int i = 0; i < 5; i++) {company.code();System.out.println(Thread.currentThread().getName() + \":我要不要休息一会?\");Thread.yield();}}});lisi.setName(\"李四\");Thread xingzhengGirl = new Thread(() -> {// Object代表维修工具synchronized (new Object()) {for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName() + \":打扫办公桌\");Thread.yield();}}});xingzhengGirl.setName(\"行政女秘书\");zhangsan.start();lisi.start();xingzhengGirl.start();}}

执行结果:(yield出让时间片不稳定,可多次尝试查看效果)
张三:编码中!
张三:我要不要休息一会?
张三:编码中!
张三:我要不要休息一会?
张三:编码中!
张三:我要不要休息一会?
张三:编码中!
张三:我要不要休息一会?
张三:编码中!
张三:我要不要休息一会?
行政女秘书:打扫办公桌
行政女秘书:打扫办公桌
行政女秘书:打扫办公桌
李四:编码中!
李四:我要不要休息一会?
李四:编码中!
李四:我要不要休息一会?
李四:编码中!
李四:我要不要休息一会?
李四:编码中!
李四:我要不要休息一会?
李四:编码中!
李四:我要不要休息一会?
行政女秘书:打扫办公桌
行政女秘书:打扫办公桌

  1. join方法是Thread对象方法,底层调用的Object的wait方法,调用后,当前线程等待join线程完成任务后再进行工作,相当于现实中,两位同事需要协作完成工作。
    以下为代码示例:
package org.loyuru.multi.thread.composite;/*** 张三要做PPT,需要李四上网查资料并放到U盘中,给他** @author Teddy Lee* @date 2020年3月16日*/public class Company4 {private int computer = 0;public synchronized void ppt() {System.out.println(Thread.currentThread().getName() + \":编写PPT完成!\");}public synchronized void material() {for (int i = 0; i < 10; i++) {switch (i) {case 0:System.out.println(Thread.currentThread().getName() + \":第\" + i + \"步,查资料!\");break;case 8:System.out.println(Thread.currentThread().getName() + \":第\" + i + \"步,存到U盘!\");break;case 9:System.out.println(Thread.currentThread().getName() + \":第\" + i + \"步,交资料!\");break;default:System.out.println(Thread.currentThread().getName() + \":第\" + i + \"步,XXX!\");}}}public static void main(String[] args) {Company4 boss = new Company4();Thread lisi = new Thread(() -> {boss.material();});lisi.setName(\"李四\");Thread zhangsan = new Thread(() -> {System.out.println(Thread.currentThread().getName() + \":准备编写PPT!\");try {lisi.join();} catch (InterruptedException e) {e.printStackTrace();}boss.ppt();});zhangsan.setName(\"张三\");zhangsan.start();lisi.start();}}

结果:
张三:准备编写PPT!
李四:第0步,查资料!
李四:第1步,XXX!
李四:第2步,XXX!
李四:第3步,XXX!
李四:第4步,XXX!
李四:第5步,XXX!
李四:第6步,XXX!
李四:第7步,XXX!
李四:第8步,存到U盘!
李四:第9步,交资料!
张三:编写PPT完成!

赞(0) 打赏
未经允许不得转载:爱站程序员基地 » 多线程wait/notify与sleep/yield/join的通俗理解