从名字推敲
保护
回归到多线程编程的一个痛点就是共享资源的多线程访问修改的安全问题,所以这里保护就是指的共享资源, 那么在java的synchronized的关键字需要标识一个共享资源代码块的一个安全需要一个 对象,这个对象头会指向一个monitor对象,monitor对象通过操作系统的互斥锁来实现线程之间的同步问题,也就对共享资源(同步代码块)进行了保护。
暂挂
暂挂是啥意思呢, 就是说把当前线程虽然拥有了共享资源的访问锁,但是在对共享资源访问发现这个资源还没有变成自己想要的那个状态,所以这个时候,当前线程需要把自己挂起,也就是wait, 释放锁,等着另一个线程获取倒锁,如何修改共享资源状态之后在唤醒自己,
那这里有一个问题,就是当前线程唤醒之后,虽然共享资源的状态被别的线程已经改了,但是一定是自己想要的吗,不一定吧,所以还要继续判断, 在具体编程的时候需要while循环判断(其实也就是避免虚假唤醒的问题)
示例模拟
/**
* 模拟服务资源请求对象
* @Author: puhaiguo
* @Date: 2022-07-10 17:59
* @Version 1.0
*/
public class Request {
private String name;
private String date;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
}
package com.manythread.threaddesign.three;
import java.util.LinkedList;
import java.util.Queue;
/**
* 请求队列
* @Author: puhaiguo
* @Date: 2022-07-10 18:00
* @Version 1.0
*/
public class RequestQueue {
private Queue<Request> queue = new LinkedList();
/*生产*/
public synchronized void putRequest(Request request){
queue.add(request);
notify();
}
/*消费*/
public synchronized Request getRequest(){
while (queue.isEmpty()){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return queue.remove();
}
}
package com.manythread.threaddesign.three;
/**
* 请求线程
* @Author: puhaiguo
* @Date: 2022-07-10 18:03
* @Version 1.0
*/
public class RequestThread extends Thread{
private RequestQueue requestQueue;
private Request request;
public RequestThread(RequestQueue requestQueue, Request request) {
this.requestQueue = requestQueue;
this.request = request;
}
@Override
public void run() {
requestQueue.putRequest(request);
}
}
package com.manythread.threaddesign.three;
/**
* 服务端线程
* @Author: puhaiguo
* @Date: 2022-07-10 18:05
* @Version 1.0
*/
public class ServerThread extends Thread{
private RequestQueue requestQueue;
public ServerThread(RequestQueue requestQueue) {
this.requestQueue = requestQueue;
}
@Override
public void run() {
Request request = requestQueue.getRequest();
System.out.println(String.format("%s 收到 %s 的请求", request.getDate(), request.getName()));
}
}
package com.manythread.threaddesign.three;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
*
* @Author: puhaiguo
* @Date: 2022-07-10 18:07
* @Version 1.0
*/
public class Test {
public static void main(String[] args) throws InterruptedException {
RequestQueue requestQueue = new RequestQueue();
Request request = new Request();
LocalDateTime now = LocalDateTime.now();
request.setDate(now.format(DateTimeFormatter.ofPattern("yyyy--HH--ss")));
request.setName("足球小子");
RequestThread requestThread = new RequestThread(requestQueue, request);
ServerThread serverThread = new ServerThread(requestQueue);
serverThread.start();
TimeUnit.SECONDS.sleep(2);
requestThread.start();
}
}
总结
以上示例用到了
单线程模式,保护性暂挂模式,呃怎么说呢,保护性暂挂模式和生产者消费者模式有点类似。