同步模式之保护性暂停
定义:
Guarded Suspension 用在一个线程等待另一个线程的执行结果
要点:
有一个结果需要从一个线程传递到另一个线程,让他们关联同一个 GuardedObject
如果有结果源源不断的从一个线程到另一个线程,可以使用消息队列(生产者消费者)
JDK中join Future的实现,采用这个模式
因为要等待另一方的结果,归类到同步模式
例子:
线程一等待线程二的结果
public class Test01 {
public static void main(String[] args) {
//线程一等待线程二的结果
GuardedObject guardedObject = new GuardedObject();
new Thread(()->{
//等待结果
System.out.println(Thread.currentThread().getName()+"等待结果");
int re = (int)guardedObject.get();
System.out.println("结果为:"+re);
}).start();
new Thread(()->{
//产生结果
System.out.println(Thread.currentThread().getName()+"正在产生结果");
guardedObject.complete(1+1);
}).start();
}
}
class GuardedObject{
//结果
private Object response;
//获取结果
public Object get(){
synchronized (this){
//没有结果就等待
while (response==null){
try {
this.wait();//等待产生结果,线程1等待结果的产生
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return response;
}
}
//产生结果
public void complete(Object response){
synchronized (this){
//给结果赋值线程2调用这个方法,赋值
this.response=response;
this.notifyAll();
}
}
}
优化:
不能无限制的等待
//获取结果
//timeout 表示要等待多久,如果时间超过,就不等了
public Object get(long timeout){
//记录开始的时间
long begin=System.currentTimeMillis();
//经历的时间
long passedTime = 0;
synchronized (this){
//没有结果
while (response==null){
//如果经历的时间超过最大等待的时间,退出循环
if (passedTime>=timeout){
break;
}
try {
this.wait(timeout-passedTime);//避免虚假唤醒导致时间变长
} catch (InterruptedException e) {
e.printStackTrace();
}
//求得经过的时间
passedTime=System.currentTimeMillis()-begin;
}
return response;
}
}
测试
最长等待2s
但是下载需要3s
等待两秒就不再等待了,
public class Test02 {
public static void main(String[] args) {
//线程一等待线程二的结果
GuardedObject_ guardedObject = new GuardedObject_();
new Thread(()->{
//等待结果
System.out.println(Thread.currentThread().getName()+"等待结果");
Object re=guardedObject.get(2000);
System.out.println("结果为:"+re);
}).start();
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"正在产生结果");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
guardedObject.complete(1+1);
}).start();
}
}
//增加超时效果
class GuardedObject_{
//结果
private Object response;
//获取结果
//timeout 表示要等待多久,如果时间超过,就不等了
public Object get(long timeout){
//记录开始的时间
long begin=System.currentTimeMillis();
//经历的时间
long passedTime = 0;
synchronized (this){
//没有结果
while (response==null){
//如果经历的时间超过最大等待的时间,退出循环
if (passedTime>=timeout){
break;
}
try {
this.wait(timeout-passedTime);//避免虚假唤醒导致时间变长
} catch (InterruptedException e) {
e.printStackTrace();
}
//求得经过的时间
passedTime=System.currentTimeMillis()-begin;
}
return response;
}
}
//产生结果
public void complete(Object response){
synchronized (this){
//给结果赋值
this.response=response;
this.notifyAll();
}
}
}
异步模式之生产者消费者模式
不需要产生结果和消费结果的线程一一对应
消费队列可以用来平衡生产和消费的线程资源
生产者仅仅负责产生结果数据,消费者专心处理结果数据
消息队列是有容量限制的,满的时候不在加入数据,空的时候不在消耗数据
JDK中各种阻塞队列,采用这种模式
public class ProducerConsumer_ {
public static void main(String[] args) {
MessageQueue queue = new MessageQueue(2);
for (int i = 0; i < 3; i++) {
int id =i;
new Thread(()->{
queue.put(new Message(id,"值"+id));
},"生产者"+i).start();
}
new Thread(()->{
while (true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Message message = queue.take();
}
},"消费者").start();
}
}
//消息队列类 java线程中通信
class MessageQueue{
//消息队列集合
private LinkedList<Message> list = new LinkedList<>();
//队列容量
private int capcity;
//手动传入容量
public MessageQueue(int capcity){
this.capcity=capcity;
}
//获取消息
public Message take(){
//检查对象是否为空
synchronized (list){
//队列是空的时候,进行等待
while (list.isEmpty()){
try {
System.out.println("队列为空,消费者等待");
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//从队列头部获取消息并返回
Message message=list.removeFirst();
System.out.println("已消费消息:"+message);
list.notifyAll();
return message;
}
}
//存入消息
public void put(Message message){
//检查是不是满了
synchronized (list){
while (list.size()==capcity){
try {
System.out.println("队列已满,"+Thread.currentThread().getName()+"等待");
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//数据放到尾部
list.addLast(message);
System.out.println(Thread.currentThread().getName()+"已生产消息"+message);
list.notifyAll();
}
}
}
//消息
class Message{
private int id;
private Object value;
public Message(int id, Object value) {
this.id = id;
this.value = value;
}
public int getId() {
return id;
}
public Object getValue() {
return value;
}
@Override
public String toString() {
return "Message{" +
"id=" + id +
", value=" + value +
'}';
}
}