1.同步模式-普通版
定义GuardedObject1
class GuardedObject1 {
private Object response;
private final Object lock=new Object();
//获得消息
public Object get() throws Exception{
synchronized (lock){
while (true){
if(response==null){
lock.wait();
}else {
return response;
}
}
}
}
//生产消息
public Object set(Object o){
synchronized (lock){
response=o;
lock.notify();
return o;
}
}
}
测试
一个线程等待另一个线程的执行结果
public static void main(String[] args) {
GuardedObject guardedObject=new GuardedObject();
log.debug("当前时间");
new Thread(()->{
try {
log.debug(String.valueOf(guardedObject.get()));
} catch (Exception e) {
e.printStackTrace();
}
},"t1").start();
new Thread(()->{
try {
Thread.sleep(1000);
log.debug("设置消息");
guardedObject.set("hello juc");
} catch (Exception e) {
e.printStackTrace();
}
},"t2").start();
}
执行结果
00:58:50 [main] c.Demo4 - 当前时间
00:58:51 [t2] c.Demo4 - 设置消息
00:58:51 [t1] c.Demo4 - hello juc
2.同步模式-超时版
定义GuardedObject2
class GuardedObject2 {
private Object response;
private final Object lock=new Object();
//获得消息
public Object get(Long l) throws Exception{
synchronized (lock){
Long start=System.currentTimeMillis();
Long now=0L;
Long need=0l;
while (true){
now=System.currentTimeMillis();
need=l-(now-start);
if(need<=0){
log.debug("消息为null超时结束");
break;
}
if(response==null){
lock.wait(need);
}else {
return response;
}
}
}
return "超时返回";
}
//生产消息
public Object set(Object o){
synchronized (lock){
response=o;
lock.notify();
return o;
}
}
}
测试:没有超时
public static void main(String[] args) {
GuardedObject2 guardedObject=new GuardedObject2();
log.debug("当前时间");
new Thread(()->{
try {
System.out.println(guardedObject.get(5000l));
} catch (Exception e) {
e.printStackTrace();
}
},"t1").start();
new Thread(()->{
try {
Thread.sleep(4000);
log.debug("设置消息");
guardedObject.set("hello juc");
} catch (Exception e) {
e.printStackTrace();
}
},"t2").start();
}
测试:超时
public static void main(String[] args) {
GuardedObject2 guardedObject=new GuardedObject2();
log.debug("当前时间");
new Thread(()->{
try {
System.out.println(guardedObject.get(3000l));
} catch (Exception e) {
e.printStackTrace();
}
},"t1").start();
new Thread(()->{
try {
Thread.sleep(4000);
log.debug("设置消息");
guardedObject.set("hello juc");
} catch (Exception e) {
e.printStackTrace();
}
},"t2").start();
}
输出
00:50:37 [main] c.Demo4 - 当前时间
00:50:41 [t2] c.Demo4 - 设置消息
00:50:41 [t1] c.Demo4 - hello juc
00:51:04 [main] c.Demo4 - 当前时间
00:51:07 [t1] c.Demo3 - 消息为null超时结束
00:51:07 [t1] c.Demo4 - 超时返回
00:51:08 [t2] c.Demo4 - 设置消息
3.同步模式-多任务版
图中 Futures 就好比居民楼一层的信箱(每个信箱有房间编号),左侧的 t0,t2,t4 就好比等待邮件的居民,右 侧的 t1,t3,t5 就好比邮递员 。
如果需要在多个类之间使用 GuardedObject3对象,作为参数传递不是很方便,因此设计一个用来解耦的中间类, 这样不仅能够解耦【结果等待者】和【结果生产者】,还能够同时支持多个任务的管理。
新增 id 用来标识 Guarded Object3
/**
* 快递格子
*/
@Slf4j(topic = "c.four-Demo3")
class GuardedObject3{
private Object response;
private final Object lock=new Object();
public GuardedObject3(int id) {
this.id = id;
}
private int id;
public int getId() {
return id;
}
//获得消息
public Object get(Long l) throws Exception{
synchronized (lock){
Long start=System.currentTimeMillis();
Long now=0L;
Long need=0l;
while (true){
now=System.currentTimeMillis();
need=l-(now-start);
if(need<=0){
log.debug("消息为null超时结束");
break;
}
if(response==null){
lock.wait(need);
}else {
return response;
}
}
}
return "超时返回";
}
//生产消息
public Object set(Object o){
synchronized (lock){
response=o;
lock.notifyAll();
return o;
}
}
}
中间解耦类
/**
* 快递柜
*/
class Mailboxes{
private static int i=0;
static Map<Integer,GuardedObject3> m=new Hashtable<>();
public static synchronized int getId(){
return ++i;
}
//取件人创建快递格子
public static GuardedObject3 create(){
GuardedObject3 guardedObject3=new GuardedObject3(getId());
m.put(guardedObject3.getId(),guardedObject3);
return guardedObject3;
}
//送信人获取快递格子
public static GuardedObject3 getGuardedObject3(int id){
return m.remove(id);
}
//送信人获取格子集合
public static synchronized Set<Integer> getIds(){
return m.keySet();
}
}
业务相关类
/**
* 取件人
*/
@Slf4j(topic = "c.four-Demo3")
class Person extends Thread{
@Override
public void run(){
GuardedObject3 guardedObject3 = Mailboxes.create();
try {
Object o = guardedObject3.get(3000l);
log.debug("收到信:"+o);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 送信人
*/
class Postman extends Thread{
private int id;
Postman(int id){
this.id=id;
}
@Override
public void run() {
GuardedObject3 guardedObject3 = Mailboxes.getGuardedObject3(id);
guardedObject3.set("来信了"+id);
}
}
测试
public static void main(String[] args)throws Exception{
log.debug("开始");
for (int i = 0; i < 5; i++) {
new Person().start();
}
TimeUnit.SECONDS.sleep(2);
for (Integer id : Mailboxes.getIds()) {
new Postman(id).start();
}
}
}
某次运行结果
11:46:47 [main] c.four-Demo3 - 开始
11:46:49 [Thread-3] c.four-Demo3 - 收到信:来信了5
11:46:49 [Thread-1] c.four-Demo3 - 收到信:来信了4
11:46:49 [Thread-2] c.four-Demo3 - 收到信:来信了3
11:46:49 [Thread-4] c.four-Demo3 - 收到信:来信了2
11:46:49 [Thread-0] c.four-Demo3 - 收到信:来信了1
4.异步模式-生产者/消费者
1.定义
此处定义了解耦的队列,生产者不再需要等待消费者消费完,故称此模式为异步模式
要点
- 与前面的保护性暂停中的 GuardObject 不同,不需要产生结果和消费结果的线程一一对应
- 消费队列可以用来平衡生产和消费的线程资源
- 生产者仅负责产生结果数据,不关心数据该如何处理,而消费者专心处理结果数据
- 消息队列是有容量限制的,满时不会再加入数据,空时不会再消耗数据
- JDK 中各种阻塞队列,采用的就是这种模式
2.实现
/**
* 消息对象
*/
class Message{
private int id;
private String message;
public Message(int id, String message) {
this.id = id;
this.message = message;
}
public int getId() {
return id;
}
public String getMessage() {
return message;
}
}
/**
* 消息队列
*/
@Slf4j(topic = "c.four-Demo4")
class MessageQueue{
private LinkedList<Message> linkedList;
private int length;
public MessageQueue(int length) {
this.linkedList=new LinkedList<>();
this.length=length;
}
//生产消息
public void product(Message message) throws InterruptedException {
synchronized (linkedList){
while(linkedList.size()>=length){
log.debug("库存积压");
linkedList.wait();
}
log.debug("生产消息:"+message.getMessage());
linkedList.add(message);
linkedList.notifyAll();
}
}
//消费消息
public Message consumer() throws InterruptedException {
synchronized (linkedList){
while(linkedList.size()<=0){
log.debug("没货了");
linkedList.wait();
}
Message remove = linkedList.remove();
log.debug("消费消息:"+remove.getMessage());
linkedList.notifyAll();
return remove;
}
}
}
3.测试
public static void main(String[] args) {
MessageQueue messageQueue=new MessageQueue(2);
for (int i = 0; i < 4; i++) {
int id=i;
new Thread(()->{
try {
messageQueue.product(new Message(id,"消息"+id));
} catch (InterruptedException e) {
e.printStackTrace();
}
},"product"+i).start();
}
new Thread(()->{
while (true){
try {
messageQueue.consumer();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"consumer").start();
}
某次运行结果
13:36:25 [product1] c.four-Demo4 - 生产消息:消息1
13:36:25 [consumer] c.four-Demo4 - 消费消息:消息1
13:36:25 [consumer] c.four-Demo4 - 没货了
13:36:25 [product0] c.four-Demo4 - 生产消息:消息0
13:36:25 [product2] c.four-Demo4 - 生产消息:消息2
13:36:25 [product3] c.four-Demo4 - 库存积压
13:36:25 [consumer] c.four-Demo4 - 消费消息:消息0
13:36:25 [consumer] c.four-Demo4 - 消费消息:消息2
13:36:25 [consumer] c.four-Demo4 - 没货了
13:36:25 [product3] c.four-Demo4 - 生产消息:消息3
13:36:25 [consumer] c.four-Demo4 - 消费消息:消息3
13:36:25 [consumer] c.four-Demo4 - 没货了