1. 單例模式
- 單例模式是一種對象創(chuàng)建模式权埠,用于產(chǎn)生一個(gè)對象的具體實(shí)例榨了,確保系統(tǒng)中一個(gè)類只產(chǎn)生一個(gè)實(shí)例。有兩大好處:
- 對于頻繁使用的對象攘蔽,可以省略new操作花費(fèi)的時(shí)間阻逮,對于一些重量級對象,是一筆可觀的系統(tǒng)開銷秩彤。
- 減輕GC壓力叔扼,縮短GC停頓時(shí)間。
//內(nèi)存開銷大漫雷,并發(fā)不安全
class Single1{
private static final Single1 SINGLE1 = new Single1();
private Single1() {
}
public static Single1 getInstance() {
return SINGLE1;
}
}
//并發(fā)安全瓜富,有鎖性能開銷大,內(nèi)存開銷小
class Single2{
private static Single4 single2 = null;
private Single2() {
}
public static synchronized Single2 getInstance() {
if(single2 == null) {
single2 = new Single4();
}
return single2;
}
}
//丑陋降盹、復(fù)雜与柑,低版本jdk不適用
class Single3{
private static volatile Single3 single3;
private Single3() {
}
public static Single3 getInstance() {
if(single3 == null) {
synchronized(Single3.class) {
if(single3 == null) {
single3 = new Single3();
}
}
}
return single3;
}
}
//并發(fā)安全,無鎖性能高,內(nèi)存開銷小价捧,巧妙利用虛擬機(jī)類加載機(jī)制
class Single4{
private Single4() {
}
private static class Inner{
private static final Single4 SINGLE4 = new Single3();
}
public static Single4 getInstance() {
return Inner.SINGLE4;
}
}
2. 不變模式
- 加鎖操作有一定的性能損耗丑念。
- 不變模式:天生多線程友好的。一旦對象被創(chuàng)建结蟋,則它的內(nèi)部狀態(tài)將永遠(yuǎn)不會發(fā)生改變脯倚。沒有任何一個(gè)線程可以修改其內(nèi)部狀態(tài)和數(shù)據(jù),同時(shí)其內(nèi)部狀態(tài)也不會發(fā)生改變嵌屎。
- 只讀屬性:只讀屬性不會被其他修改推正,但是自身有可能變化,比如對象的存活時(shí)間會隨著時(shí)間推移變化宝惰。
- 不變模式的主要使用場景需要滿足兩個(gè)條件:
- 當(dāng)對象創(chuàng)建后植榕,其內(nèi)部狀態(tài)和數(shù)據(jù)不再發(fā)生任何變化。
- 對象需要被共享尼夺,被多線程頻繁訪問尊残。
【如何實(shí)現(xiàn)不變模式】:
- 去除setter和其他所有修改自身屬性的方法。
- 將所有屬性設(shè)為私有淤堵,并用final標(biāo)記夜郁,確保其不可修改。
- 確保沒有子類可以重載修改它的行為粘勒。
- 有一個(gè)可以創(chuàng)建完整對象的構(gòu)造函數(shù)竞端。
//final 起關(guān)鍵作用
public final class Product {
private final String no;
private final String name;
private final double price;
public Product(String no, String name, double price) {
super();
this.no = no;
this.name = name;
this.price = price;
}
public String getNo() {
return no;
}
public String getName() {
return name;
}
public double getPrice() {
return price;
}
}
主要不變模式:
java.lang.String
java.lang.Boolean
java.lang.Byte
java.lang.Character
java.lang.Double
java.lang.Float
java.lang.Integer
java.lang.Long
java.lang.Short
3. 生產(chǎn)者-消費(fèi)者模式
- 生產(chǎn)者-消費(fèi)者模式提供了多線程間協(xié)作的良好解決方案。生產(chǎn)者負(fù)責(zé)提交用戶請求庙睡,消費(fèi)者負(fù)責(zé)處理任務(wù)事富,兩者通過共享內(nèi)存緩沖區(qū)進(jìn)行通信。
- 內(nèi)存緩沖區(qū)避免了生產(chǎn)者和消費(fèi)者的直接通信乘陪,從而將生產(chǎn)者和消費(fèi)者解耦统台。同時(shí)允許生產(chǎn)者和消費(fèi)者在執(zhí)行速度上存在時(shí)間差。
BlockingQueue實(shí)現(xiàn)生產(chǎn)者和消費(fèi)者是一個(gè)不錯(cuò)的選擇啡邑,但是BlockingQueue并不是一個(gè)高性能的實(shí)現(xiàn)贱勃,它完全使用鎖和阻塞等待來實(shí)現(xiàn)線程間的同步。在高并發(fā)場合谤逼,它的性能不是特別的優(yōu)越贵扰。可以用無鎖的Disruptor實(shí)現(xiàn)流部。Disruptor使用無鎖的方式實(shí)現(xiàn)了一個(gè)環(huán)形隊(duì)列戚绕,生產(chǎn)者和消費(fèi)者都是用CAS操作來處理環(huán)形隊(duì)列中的數(shù)據(jù)。
4. Future模式
- 核心思想是異步調(diào)用枝冀,當(dāng)我們需要調(diào)用一個(gè)函數(shù)方法時(shí)舞丛,如果這個(gè)函數(shù)執(zhí)行很慢而我們又不是立刻需要結(jié)果耘子,可以讓被調(diào)者立刻返回,讓他在后臺慢慢處理這個(gè)請求球切,對調(diào)用者來說谷誓,可以先處理一些其他任務(wù),在真正需要數(shù)據(jù)的場合再去嘗試獲得需要的數(shù)據(jù)吨凑。
public interface Data {
public String getResult();
}
//FutrureData是RealData的虛擬實(shí)現(xiàn)捍歪,可以很快被構(gòu)造并返回。如果數(shù)據(jù)沒準(zhǔn)備好怀骤,那么程序會阻塞费封。
public class FutureData implements Data {
protected RealData realData = null;
protected boolean isReady = false;
public synchronized void setRealData(RealData realData) {
if(isReady) {
return;
}
this.realData = realData;
isReady = true;
notifyAll();
}
@Override
public synchronized String getResult() {
while(!isReady) {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return realData.result;
}
}
public class RealData implements Data{
protected final String result;
public RealData(String para) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 10; i++) {
sb.append(para);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
result = sb.toString();
}
@Override
public String getResult() {
return result;
}
}
public class Client {
public Data request(final String queryStr) {
final FutureData futureData = new FutureData();
new Thread() {
public void run() {
RealData realData = new RealData(queryStr);
futureData.setRealData(realData);
}
}.start();
return futureData;
}
}
public class Main {
public static void main(String[] args) {
Client client = new Client();
Data data = client.request("name");
System.out.println("請求完畢");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("真實(shí)數(shù)據(jù)"+data.getResult());
}
}
5. JDK的Future
image.png
public interface Callable<V> {
V call() throws Exception;
}
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}
public class CallableDemo implements Callable<Integer> {
private int sum;
@Override
public Integer call() throws Exception {
System.out.println("Callable子線程開始計(jì)算啦焕妙!");
Thread.sleep(2000);
for(int i=0 ;i<5000;i++){
sum=sum+i;
}
System.out.println("Callable子線程計(jì)算結(jié)束蒋伦!");
return sum;
}
}
ExecutorService es = Executors.newSingleThreadExecutor();
//創(chuàng)建Callable對象任務(wù)
CallableDemo calTask=new CallableDemo();
//提交任務(wù)并獲取執(zhí)行結(jié)果
Future<Integer> future =es.submit(calTask);
//關(guān)閉線程池
es.shutdown();
ExecutorService es = Executors.newSingleThreadExecutor();
//創(chuàng)建Callable對象任務(wù)
CallableDemo calTask=new CallableDemo();
//創(chuàng)建FutureTask
FutureTask<Integer> futureTask=new FutureTask<>(calTask);
//執(zhí)行任務(wù)
es.submit(futureTask);
//關(guān)閉線程池
es.shutdown();