在分布式开发中,除了常规的23种设计模式外,还有一些针对并发场景的常用设计模式,本文将对这些模式进行详细介绍。
1. 单例模式(singleton)
- 概念:确保一个类只有一个实例,并提供一个全局访问点来获取该实例。
-
原理:
- 私有构造函数:防止外部通过new关键字创建类的实例。
- 静态实例变量:保存类的唯一实例。
- 全局访问点:通常是一个静态方法,用于获取类的实例。
-
并发代码示例:
public class singleton { private static volatile singleton instance; private singleton() { // 私有构造函数 } public static singleton getinstance() { if (instance == null) { // 第一次检查 synchronized (singleton.class) { // 同步锁 if (instance == null) { // 第二次检查 instance = new singleton(); } } } return instance; } }
- 概念:一旦创建了一个对象,其状态就不能被修改。
-
原理:
- 所有属性都是final的:这意味着一旦初始化后,属性值不能被改变。
- 不提供修改状态的方法:不可变对象不提供任何可以修改其状态的方法。
- 通过构造函数初始化所有属性:在对象创建时,必须通过构造函数初始化所有属性。
- 深度复制:如果对象包含可变对象,需要确保这些对象在创建时也是不可变的,或者在返回时创建它们的副本。
-
并发代码示例:
public final class immutableperson { private final string name; private final int age; public immutableperson(string name, int age) { this.name = name; this.age = age; } public string getname() { return name; } public int getage() { return age; } public immutableperson setname(string newname) { return new immutableperson(newname, age); } public immutableperson setage(int newage) { return new immutableperson(name, newage); } }
3. 线程局部存储模式(thread local storage)
- 概念:允许在多线程环境下为每个线程维护一个独立的变量副本。
-
原理:
-
并发代码示例:
public class threadlocalexample { // 定义一个threadlocal变量,用于存储线程级别的变量 private static final threadlocal<string> threadlocal = new threadlocal<string>(); public static void setthreadlocalvalue(string value) { threadlocal.set(value); } public static string getthreadlocalvalue() { return threadlocal.get(); } public static void main(string[] args) { // 在主线程中设置和获取threadlocal变量的值 setthreadlocalvalue("main thread value"); system.out.println("main thread value: " + getthreadlocalvalue()); // 创建一个新线程并设置和获取threadlocal变量的值 thread thread = new thread(() -> { setthreadlocalvalue("child thread value"); system.out.println("child thread value: " + getthreadlocalvalue()); }); thread.start(); } }
4. 生产者-消费者模式(producer-consumer)
- 概念:将数据的生成(生产者)和数据的处理(消费者)分离来解决并发问题。
-
原理:
-
并发代码示例:
import java.util.concurrent.blockingqueue; import java.util.concurrent.linkedblockingqueue; class producer implements runnable { private final blockingqueue<integer> queue; public producer(blockingqueue<integer> q) { queue = q; } public void run() { try { for (int i = 0; i < 10; i++) { queue.put(i); system.out.println("produced: " + i); } } catch (interruptedexception ex) { ex.printstacktrace(); } } } class consumer implements runnable { private final blockingqueue<integer> queue; public consumer(blockingqueue<integer> q) { queue = q; } public void run() { try { while (true) { int value = queue.take(); system.out.println("consumed: " + value); } } catch (interruptedexception ex) { ex.printstacktrace(); } } } public class producerconsumerexample { public static void main(string[] args) { blockingqueue<integer> queue = new linkedblockingqueue<integer>(10); producer producer = new producer(queue); consumer consumer = new consumer(queue); new thread(producer).start(); new thread(consumer).start(); } }
5. 读者-写者模式(read-write lock)
- 概念:允许多个读者同时访问数据,但在写者访问时,其他的读者或写者都会被阻塞。
-
原理:
-
并发代码示例:
import java.util.concurrent.locks.readwritelock; import java.util.concurrent.locks.reentrantreadwritelock; class sharedresource { private final readwritelock readwritelock = new reentrantreadwritelock(); private final lock readlock = readwritelock.readlock(); private final lock writelock = readwritelock.writelock(); private string data; public void read() { readlock.lock(); try { // 读取数据 system.out.println("reading data: " + data); } finally { readlock.unlock(); } } public void write(string newdata) { writelock.lock(); try { // 写入数据 data = newdata; system.out.println("writing data: " + data); } finally { writelock.unlock(); } } } public class readwritelockexample { public static void main(string[] args) { sharedresource resource = new sharedresource(); // 创建多个读者线程 for (int i = 0; i < 5; i++) { new thread(resource::read).start(); } // 创建写者线程 new thread(() -> resource.write("new data")).start(); } }
6. 工作队列模式(worker thread)
- 概念:将任务的提交与任务的执行分离。
-
原理:
- 任务队列:使用一个队列来存储提交的任务。
- 工作者线程:创建一组后台线程作为工作者线程,它们不断地从任务队列中取出任务并执行。
- 任务提交:客户端将任务提交到队列中,不需要关心任务的执行细节。
- 并发代码示例:
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; class Task implements Runnable { private final int taskId; public Task(int taskId) { this.taskId = taskId; } @Override public void run() {