一學(xué)一做看視頻網(wǎng)站有哪些網(wǎng)絡(luò)營銷產(chǎn)品策略分析
線程安全
- 線程安全:
- 線程安全:
- synchronized
- 同步代碼塊:
- 同步方法:
- 成員同步方法:
- 靜態(tài)同步方法:
- Lock:
- 應(yīng)用:
- 單例模式:
- 懶漢式:
- 餓漢式:
- 枚舉餓漢式:
- 雙重檢驗(yàn)鎖:
線程安全:
線程安全:
線程安全 – 加鎖
注意:要想多個(gè)線程互斥住,就必須使用同一把鎖(對象)!!!
加鎖方式:
- synchronized
- Lock
?
synchronized
- 同步代碼塊
- 同步方法
?
同步代碼塊:
數(shù)據(jù)結(jié)構(gòu):
synchronized(鎖對象){//自動上鎖...想要互斥的代碼...}//自動解鎖
?
同步方法:
- 成員同步方法
- 靜態(tài)同步方法
?
成員同步方法:
注意:鎖對象 -> this
多個(gè)子線程時(shí),調(diào)用的對象(this)不一樣,則鎖不住。
數(shù)據(jù)結(jié)構(gòu):
public synchronized void method(){//自動上鎖...想要互斥的代碼...}//自動解鎖
?
靜態(tài)同步方法:
注意:鎖對象 -> 類.class
public static synchronized void method(){//自動上鎖...想要互斥的代碼...}//自動解鎖
?
?
Lock:
//鎖對象Lock lock = new ReentrantLock();lock.lock();//手動上鎖...想要互斥的代碼...lock.unlock();//手動解鎖
?
應(yīng)用:
public class MyThread extends Thread{private static int allTicket = 1000;private static int curTicket = 0;private static Lock lock = new ReentrantLock();public MyThread(String name) {super(name);}@Overridepublic void run() {while(curTicket < allTicket){lock.lock();//手動上鎖try {if(curTicket < allTicket){curTicket++;System.out.println("窗口" + Thread.currentThread().getName() + "正在銷售第" + curTicket + "張票");}if(curTicket >= allTicket){System.out.println("窗口" + Thread.currentThread().getName() + "票已經(jīng)售完");}} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();//手動解鎖}}}}
public static void main(String[] args) {MyThread t1 = new MyThread("001");MyThread t2 = new MyThread("002");MyThread t3 = new MyThread("003");t1.start();t2.start();t3.start();}
?
?
單例模式:
該類的對象在整個(gè)項(xiàng)目中只創(chuàng)建一次(只實(shí)例化一次)。
?
懶漢式:
單例模式(懶漢式)不是線程安全的。
public class A {//聲明對象名private static A a;private A(){}public static A getIntance(){//判斷對象為空,再創(chuàng)建對象if(a == null){a = new A();}return a;}
}
public static void main(String[] args) {A a1 = A.getIntance();A a2 = A.getIntance();A a3 = A.getIntance();A a4 = A.getIntance();//地址都是一樣的,則是一個(gè)對象System.out.println(a1);System.out.println(a2);System.out.println(a3);System.out.println(a4);}
?
?
餓漢式:
單例模式(餓漢式)是線程安全的。
public class A {//先創(chuàng)建對象private static A a = new A();private A(){}public static A getIntance(){return a;}public static void method(){System.out.println("用良心做教育");}
}
public static void main(String[] args) {A a1 = A.getIntance();A a2 = A.getIntance();A a3 = A.getIntance();A a4 = A.getIntance();System.out.println(a1);System.out.println(a2);System.out.println(a3);System.out.println(a4);}
?
?
缺點(diǎn):如果只調(diào)用了類里的靜態(tài)方法,沒用到單例對象,就是浪費(fèi)空間。
public static void main(String[] args) {A.method();}
?
?
枚舉餓漢式:
枚舉單例模式(餓漢式)是線程安全的。
public enum A {//public static final A a = new A();a;private A(){}public static A getIntance(){return a;}public static void method(){System.out.println("用良心做教育");}@Overridepublic String toString() {return String.valueOf(a.hashCode());}
}
public static void main(String[] args) {A a1 = A.getIntance();A a2 = A.getIntance();A a3 = A.getIntance();A a4 = A.getIntance();System.out.println(a1);System.out.println(a2);System.out.println(a3);System.out.println(a4);}
?
?
缺點(diǎn):如果只調(diào)用了枚舉里的靜態(tài)方法,沒用到單例對象,就是浪費(fèi)空間。
public static void main(String[] args) {A.method();}
?
?
雙重檢驗(yàn)鎖:
項(xiàng)目中使用的單例模式------->雙重檢驗(yàn)鎖。
雙重檢驗(yàn)鎖的單例模式是線程安全的。
volatile – 防止指令重排
?
創(chuàng)建對象的過程:? a.開辟空間 ----- new 對象() – 0x001
? b.調(diào)用構(gòu)造方法 – 初始化數(shù)據(jù)
? c.將空間賦值給引用 – 類型 引用 = 0x001
?
創(chuàng)建對象的步驟:a/b/c 或 a/c/b
?
注意:如果創(chuàng)建對象的步驟是a/c/b,多線程的情況下可能會導(dǎo)致獲取的屬性為null
?
解決方案:使用volatile,防止指令重排,創(chuàng)建的步驟必須按照a/b/c
public class A {private static volatile A a;private A(){}public static A getIntance(){if(a == null){synchronized (A.class) {if(a == null){a = new A();}}}return a;}// public static A getIntance(){
//
// if(a != null){
// return a;
// }
// synchronized (A.class) {
// if(a == null){
// a = new A();
// }
// }
// return a;
// }
}
public static void main(String[] args) {A a1 = A.getIntance();A a2 = A.getIntance();A a3 = A.getIntance();A a4 = A.getIntance();System.out.println(a1);System.out.println(a2);System.out.println(a3);System.out.println(a4);}