并發(fā)模式
Ⅰ 同步模式——保護(hù)性暫停模式(Guarded Suspension)
用在一個(gè)線程等待另一個(gè)線程的執(zhí)行結(jié)果。JDK中join和Future的實(shí)現(xiàn)就是采用此模式

實(shí)現(xiàn)代碼(不帶超時(shí)):
package com.ljh2.guardedSuspension;
/**
*不帶超時(shí)
* Created by LJH on 2020/12/27 13:54
*/
public class GuardedSuspension {
private Object response;
private final Object lock = new Object();
public Object get() {
synchronized (lock) {
while (response == null) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return response;
}
}
public void complete (Object response) {
synchronized (lock) {
this.response = response;
lock.notifyAll();
}
}
}
//測(cè)試
public class GuardedSuspensionTest1 {
public static void main(String[] args) {
GuardedSuspension guardedSuspension = new GuardedSuspension();
new Thread(()->{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
guardedSuspension.complete(null);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
guardedSuspension.complete("ljh");
},"t1").start();
Object o = guardedSuspension.get();
System.out.println(o);
}
}
get帶超時(shí)的實(shí)現(xiàn)代碼:
public class GuardedSuspension2 {
private Object response;
private final Object lock = new Object();
public Object get (long miles) {
synchronized (lock) {
//設(shè)置時(shí)間初始值
long begin = System.currentTimeMillis();
long passedTime = 0;
while (response == null) {
long waitTime = miles-passedTime;
if (waitTime <= 0 ){
System.out.println("break");
break;
}
try {
//不要忘記加入waitTime!!!
lock.wait(waitTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
//剩余還需要等待的時(shí)間
passedTime = System.currentTimeMillis()-begin;
}
return response;
}
}
public void complete (Object response) {
synchronized (lock) {
this.response = response;
lock.notifyAll();
}
}
}
//測(cè)試
public class GuardedSuspendTest2 {
public static void main(String[] args) {
GuardedSuspension2 guardedSuspension2 = new GuardedSuspension2();
new Thread( () -> {
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
guardedSuspension2.complete(null);
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
guardedSuspension2.complete("ljh");
},"t2").start();
//1950ms來不及get到"ljh"
Object o = guardedSuspension2.get(1950);
System.out.println(o);
}
}
Ⅱ 同步模式——猶豫模式(Balking)
Balking (猶豫)模式用在一個(gè)線程發(fā)現(xiàn)另一個(gè)線程或本線程已經(jīng)做了某一件相同的事,那么本線程就無需再做了,直接結(jié)束返回。可以用來實(shí)現(xiàn)線程安全的單例模式。
public final class Singleton {
private Singleton(){}
//標(biāo)記是否有了實(shí)例
private static Singleton INSTANCE = null;
private static synchronized Singleton getInstance () {
if (INSTANCE != null) {
return INSTANCE;
}
INSTANCE = new Singleton();
return INSTANCE;
}
}
Ⅲ 同步模型——順序控制
固定運(yùn)行順序:
1、wait notify版本實(shí)現(xiàn)
public class SequenceControl1 {
static final Object lock = new Object();
//標(biāo)記t2是否已經(jīng)執(zhí)行
static boolean flag = false;
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
synchronized (lock) {
if (!flag) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("1");
}
}, "t1");
Thread t2 = new Thread(() -> {
System.out.println("2");
synchronized (lock) {
flag = true;
lock.notifyAll();
}
}, "t2");
t1.start();
t2.start();
}
}
2、park unpark來實(shí)現(xiàn)(不需要上鎖和標(biāo)記flag)
public class SequenceControl2 {
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
LockSupport.park();
System.out.println("1");
}, "t1");
Thread t2 = new Thread(() -> {
System.out.println("2");
LockSupport.unpark(t1);
}, "t2");
t1.start();
t2.start();
}
}
交替打?。?/strong>
1、wait notify版本實(shí)現(xiàn)
需要另外構(gòu)造一個(gè)類
public class SequenceControl3 {
private int looptime;
private int printItem;
public SequenceControl3() {
}
public SequenceControl3(int looptime, int printItem) {
this.looptime = looptime;
this.printItem = printItem;
}
/**
*
* @param waitFlag 現(xiàn)在要打印的線程編號(hào)
* @param nextFlag 下一個(gè)要打印的線程編號(hào)
* @param str 打印的字符串
*/
public void print (int waitFlag,int nextFlag,String str) {
for (int i = 0; i < looptime; i++) {
synchronized (this) {
while (this.printItem != waitFlag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.print(str);
printItem = nextFlag;
this.notifyAll();
}
}
}
}
//測(cè)試
public class Test {
public static void main(String[] args) {
SequenceControl3 sequenceControl3 = new SequenceControl3(5, 1);
new Thread(()->{
sequenceControl3.print(1,2,"a");
},"t1").start();
new Thread(()->{
sequenceControl3.print(2,3,"b");
},"t2").start();
new Thread(()->{
sequenceControl3.print(3,1,"c");
},"t3").start();
}
}
2、Lock條件變量
public class SequenceControl4_2 extends ReentrantLock {
private int looptime;
public SequenceControl4_2(int looptime) {
this.looptime = looptime;
}
public void start (Condition condition) {
this.lock();
try{
condition.signal();
}finally {
this.unlock();
}
}
public void print (String str,Condition curCondition,Condition nextCondition) {
for (int i = 0; i < looptime; i++) {
this.lock();
try {
curCondition.await();
System.out.print(str);
nextCondition.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
this.unlock();
}
}
}
}
//測(cè)試
public class Test2 {
public static void main(String[] args) throws InterruptedException {
SequenceControl4_2 sequenceControl4_2 = new SequenceControl4_2(5);
Condition condition1 = sequenceControl4_2.newCondition();
Condition condition2 = sequenceControl4_2.newCondition();
Condition condition3 = sequenceControl4_2.newCondition();
new Thread(()->{
sequenceControl4_2.print("a",condition1,condition2);
},"t1").start();
new Thread(()->{
sequenceControl4_2.print("b",condition2,condition3);
},"t2").start();
new Thread(()->{
sequenceControl4_2.print("c",condition3,condition1);
},"t3").start();
Thread.sleep(1000);
sequenceControl4_2.start(condition1);
}
}
3、park unpark版本實(shí)現(xiàn)
public class SequenceControl5 {
private int looptime;
private Thread[] threads;
public SequenceControl5(int looptime) {
this.looptime = looptime;
}
public void setThreads(Thread[] threads) {
this.threads = threads;
}
public void print (String str) {
for (int i = 0; i < looptime; i++) {
LockSupport.park();
System.out.print(str);
LockSupport.unpark(nextThread());
}
}
private Thread nextThread() {
int index = 0;
for (int i = 0; i < threads.length; i++) {
if (threads[i] == Thread.currentThread()) {
index = i;
break;
}
}
if (index < threads.length-1) {
return threads[index+1];
} else return threads[0];
}
void begin() {
for (Thread thread : threads) {
thread.start();
}
LockSupport.unpark(threads[0]);
}
}
//測(cè)試
public class Test {
public static void main(String[] args) {
SequenceControl5 sequenceControl5 = new SequenceControl5(5);
Thread t1 = new Thread(() -> {
sequenceControl5.print("a");
}, "t1");
Thread t2 = new Thread(() -> {
sequenceControl5.print("b");
}, "t2");
Thread t3 = new Thread(() -> {
sequenceControl5.print("c");
}, "t3");
sequenceControl5.setThreads(new Thread[]{t1,t2,t3});
sequenceControl5.begin();
}
}
Ⅳ 異步模式——生產(chǎn)者/消費(fèi)者模式
- 不同于前面的保護(hù)性暫停模式,它不需要產(chǎn)生結(jié)果和消費(fèi)結(jié)果的線程一一對(duì)應(yīng)
- 生產(chǎn)者僅負(fù)責(zé)產(chǎn)生結(jié)果數(shù)據(jù),不關(guān)心數(shù)據(jù)該如何處理,而消費(fèi)者專心處理結(jié)果數(shù)據(jù)
- JDK 中各種阻塞隊(duì)列,采用的就是這種模式
//消息對(duì)象Message類
public class Message {
private int id;
private Object message;
public Message(int id, Object message) {
this.id = id;
this.message = message;
}
public int getId() {
return id;
}
public Object getMessage() {
return message;
}
@Override
public String toString() {
return "Message{" +
"id=" + id +
", message=" + message +
'}';
}
}
//MessageQueeu
public class MessageQueue {
private LinkedList<Message> messageQueue;
private int capacity;
public MessageQueue(int capacity) {
this.capacity = capacity;
messageQueue = new LinkedList<>();
}
//消費(fèi)
public Message take () {
synchronized (messageQueue) {
while (messageQueue.isEmpty()) {
System.out.println("隊(duì)列空了,生產(chǎn)者快來生產(chǎn)。。。");
try {
messageQueue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("消費(fèi)。。。");
Message message = messageQueue.removeFirst();
messageQueue.notifyAll();
return message;
}
}
public void put (Message message) {
synchronized (messageQueue) {
while (messageQueue.size() == capacity) {
System.out.println("隊(duì)列滿了,消費(fèi)者快來消費(fèi)。。。");
try {
messageQueue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("生產(chǎn)。。。");
messageQueue.addLast(message);
messageQueue.notifyAll();
}
}
}
//測(cè)試
public class Test {
public static void main(String[] args) {
MessageQueue messageQueue = new MessageQueue(2);
for (int i = 0; i < 4; i++) {
int id = i;
new Thread(()->{
messageQueue.put(new Message(id,"ljh"+id));
},"生產(chǎn)者"+i).start();
}
new Thread(()->{
while (true) {
Message message = messageQueue.take();
}
},"消費(fèi)者").start();
}
}
Ⅴ 兩階段終止模式
在一個(gè)線程 T1 中如何“優(yōu)雅”終止線程 T2?這里的【優(yōu)雅】指的是給 T2 一個(gè)料理后事的機(jī)會(huì)。注意代碼里面的catch。

1、利用isInterrupted
public class TwoPhaseTermination {
private Thread thread;
public void start() {
thread = new Thread(()->{
while (true) {
if (Thread.currentThread().isInterrupted()) {
System.out.println("料理后事");
break;
}
try {
Thread.sleep(1000);
System.out.println("保存結(jié)果");
} catch (InterruptedException e) {
//睡眠被打斷后,讓線程打斷!!!
Thread.currentThread().interrupt();
}
//執(zhí)行監(jiān)控操作
}
},"監(jiān)控線程");
thread.start();
}
public void stop() {
thread.interrupt();
}
}
//測(cè)試
public class Test {
public static void main(String[] args) throws InterruptedException {
TwoPhaseTermination twoPhaseTermination = new TwoPhaseTermination();
twoPhaseTermination.start();
Thread.sleep(3500);
twoPhaseTermination.stop();
}
}
2、利用停止標(biāo)記(volatile變量)
public class TwoPhaseTermination2 {
private Thread thread;
private volatile boolean flag = false;
public void start() {
thread = new Thread(()->{
while (true) {
if (flag) {
System.out.println("料理后事。。。");
break;
}
try {
Thread.sleep(1000);
System.out.println("保存結(jié)果");
} catch (InterruptedException e) {
//catch里面什么都不用做
}
//執(zhí)行監(jiān)控操作
}
},"監(jiān)控線程");
thread.start();
}
public void stop() {
flag = true;
thread.interrupt();
}
}
//測(cè)試
public class Test2 {
public static void main(String[] args) throws InterruptedException {
TwoPhaseTermination2 twoPhaseTermination2 = new TwoPhaseTermination2();
twoPhaseTermination2.start();
Thread.sleep(3500);
twoPhaseTermination2.stop();
}
}
Ⅵ 線程安全的單例模式
注意是私有的構(gòu)造函數(shù)

1、餓漢式單例(不利于節(jié)約資源)
public class Singleton{
private static Singleton uniqueSingleton = new Singleton();
private Singleton(){}
private Singleton getSingleton() {
return uniqueSingleton;
}
}
2、懶漢式線程安全(對(duì)獲取對(duì)象實(shí)例的方法加鎖。鎖的粒度太大,性能不好)
public class Singleton{
private static Singleton uniqueSingleton = null;
private Singleton(){}
private synchronized Singleton getSingleton() {
if (uniqueSingleton == null) {
uniqueSingleton = new Singleton();
}
return uniqueSingleton;
}
}
3、懶漢式線程安全(雙重鎖校驗(yàn),使用volatile,性能好)
public class Singleton{
private volatile static Singleton uniqueSingleton = null;
private Singleton(){}
private Singleton getSingleton() {
if (uniqueSingleton == null) {
synchronized (this.class) {
if (uniqueSingleton == null) {
uniqueSingleton = new Singleton();
}
}
}
return uniqueSingleton;
}
}
-
使用
volatile的原因:保證可見性和有序性(禁止指令重排)uniqueSingleton = new Singleton();包括三部分:① 為
uniqueSingleton分配地址空間② 初始化
uniqueSingleton③ 將
uniqueSingleton指向分配的地址空間如果不用
volatile,可能發(fā)生重排序?yàn)棰佗邰?,還沒有初始化就分配地址了,因此此時(shí)的uniqueSingleton != null,直接就返回了沒有初始化的uniqueSingletonimage-20201228145337408 如果沒有第二個(gè)
if語句,那么會(huì)發(fā)生兩次實(shí)例化
4、靜態(tài)內(nèi)部類實(shí)現(xiàn)
當(dāng) Singleton 類被加載時(shí),靜態(tài)內(nèi)部類 SingletonHolder 沒有被加載進(jìn)內(nèi)存。只有當(dāng)調(diào)用 getUniqueInstance() 方法從而觸發(fā) SingletonHolder.INSTANCE 時(shí) SingletonHolder 才會(huì)被加載,此時(shí)初始化 INSTANCE 實(shí)例,并且 JVM 能確保 INSTANCE 只被實(shí)例化一次。
這種方式不僅具有延遲初始化的好處,而且由 JVM 提供了對(duì)線程安全的支持。
public class Singleton {
private Singleton() {
}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getUniqueInstance() {
return SingletonHolder.INSTANCE;
}
}
5、使用枚舉類
Ⅶ 享元模式
包裝類、String串池、數(shù)據(jù)庫連接池
