- 面向对象设计来源于现实世界,软件中的设计均有现实的场景对应,按照人类世界来理解普通的对象与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();
}
}
执行结果:
张三:采购新电脑来了,放到了仓库里,老四你快来安装操作系统!
张三:采购新电脑来了,放到了仓库里,老四你快来安装操作系统!
张三:采购新电脑来了,放到了仓库里,老四你快来安装操作系统!
张三:采购新电脑来了,放到了仓库里,老四你快来安装操作系统!
张三:采购新电脑来了,放到了仓库里,老四你快来安装操作系统!
张三:老四,仓库已经满了,先不采购新电脑了,等你安装完了再采购!
李四:我安装了一个操作系统,仓库有空余位置了,老三你可以采购了!
李四:我安装了一个操作系统,仓库有空余位置了,老三你可以采购了!
李四:我安装了一个操作系统,仓库有空余位置了,老三你可以采购了!
李四:我安装了一个操作系统,仓库有空余位置了,老三你可以采购了!
李四:我安装了一个操作系统,仓库有空余位置了,老三你可以采购了!
李四:老三,仓库电脑都安装完成操作系统了,我等着你采购!张三:采购新电脑来了,放到了仓库里,老四你快来安装操作系统!
张三:采购新电脑来了,放到了仓库里,老四你快来安装操作系统!
张三:采购新电脑来了,放到了仓库里,老四你快来安装操作系统!
张三:采购新电脑来了,放到了仓库里,老四你快来安装操作系统!
张三:采购新电脑来了,放到了仓库里,老四你快来安装操作系统!
李四:我安装了一个操作系统,仓库有空余位置了,老三你可以采购了!
李四:我安装了一个操作系统,仓库有空余位置了,老三你可以采购了!
李四:我安装了一个操作系统,仓库有空余位置了,老三你可以采购了!
李四:我安装了一个操作系统,仓库有空余位置了,老三你可以采购了!
李四:我安装了一个操作系统,仓库有空余位置了,老三你可以采购了!
- 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();
}
}
执行结果:
张三:采购新电脑来了!
张三:我累了,睡会觉!
张三:采购新电脑来了!
张三:我累了,睡会觉!
张三:采购新电脑来了!
张三:我累了,睡会觉!
张三:采购新电脑来了!
张三:我累了,睡会觉!
张三:采购新电脑来了!
张三:我累了,睡会觉!
张三:采购新电脑来了!
张三:我累了,睡会觉!
张三:采购新电脑来了!
张三:我累了,睡会觉!
张三:采购新电脑来了!
张三:我累了,睡会觉!
张三:采购新电脑来了!
张三:我累了,睡会觉!
张三:采购新电脑来了!
张三:我累了,睡会觉!
李四:我安装了一个操作系统!
李四:我累了,睡会觉!
李四:我安装了一个操作系统!
李四:我累了,睡会觉!
李四:我安装了一个操作系统!
李四:我累了,睡会觉!
李四:我安装了一个操作系统!
李四:我累了,睡会觉!
李四:我安装了一个操作系统!
李四:我累了,睡会觉!
李四:我安装了一个操作系统!
李四:我累了,睡会觉!
李四:我安装了一个操作系统!
李四:我累了,睡会觉!
李四:我安装了一个操作系统!
李四:我累了,睡会觉!
李四:我安装了一个操作系统!
李四:我累了,睡会觉!
李四:我安装了一个操作系统!
李四:我累了,睡会觉!
- 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出让时间片不稳定,可多次尝试查看效果)
张三:编码中!
张三:我要不要休息一会?
张三:编码中!
张三:我要不要休息一会?
张三:编码中!
张三:我要不要休息一会?
张三:编码中!
张三:我要不要休息一会?
张三:编码中!
张三:我要不要休息一会?
行政女秘书:打扫办公桌
行政女秘书:打扫办公桌
行政女秘书:打扫办公桌
李四:编码中!
李四:我要不要休息一会?
李四:编码中!
李四:我要不要休息一会?
李四:编码中!
李四:我要不要休息一会?
李四:编码中!
李四:我要不要休息一会?
李四:编码中!
李四:我要不要休息一会?
行政女秘书:打扫办公桌
行政女秘书:打扫办公桌
- 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完成!