第二章 物件及變數的併發訪問
阿新 • • 發佈:2018-12-09
1 怎麼解釋什麼是“執行緒安全”與“非執行緒安全”?
非執行緒安全:多個執行緒對同一物件中的例項變數進行併發訪問時發生,會產生“髒讀”的後果,也就是取得的資料是被更改的;
執行緒安全:獲得的例項變數的值是經過同步處理的,不會出現“髒讀”現象
2.1.1方法內的變數為執行緒安全
public class HasSelfPrivateNum { private int num = 0; public void addI(String username) { try { if(username.equals("a")) { num = 100; System.out.println("a set over"); Thread.sleep(2000); }else{ num = 200; System.out.println("b set over"); } System.out.println(username+"num = "+num); }catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } //ThreadA public class ThreadA extends Thread { private HasSelfPrivateNum numRef; public ThreadA(HasSelfPrivateNum numRef) { super(); this.numRef = numRef; } public void run() { super.run(); numRef.addI("a"); } } //ThreadB public class ThreadB extends Thread { private HasSelfPrivateNum numRef; public ThreadB(HasSelfPrivateNum numRef) { super(); this.numRef = numRef; } public void run() { super.run(); numRef.addI("b"); } } //本例用來說明兩個執行緒呼叫統一物件的同一例項變數時,可能會出現“非執行緒安全問題” public class Run { public void main(String[] args) { HasSelfPrivateNum numRef = new HasSelfPrivateNum(); ThreadA athread = new ThreadA(numRef); athread.start(); ThreadB bthread = new ThreadB(numRef); bthread.start(); } }
2.1.2 例項變數非執行緒安全
只要把上例中的num的宣告移到方法外即為“非執行緒安全的”例子,處理方式:在addI方法前加“synchronized”關鍵字
ps:在兩個執行緒訪問同一物件中的同步方法時一定是執行緒安全的
2.1.3 多個物件多個鎖
public class Run1 { public static void main(String[] args) { // 兩個物件被兩個不同執行緒訪問 HasSelfPrivateNum numRef1 = new HasSelfPrivateNum(); HasSelfPrivateNum numRef2 = new HasSelfPrivateNum(); ThreadA threada = new ThreadA(numRef1); ThreadB threadb = new ThreadB(numRef2); threada.start(); threadb.start(); } }
對於多個執行緒訪問同一物件時,哪個執行緒先執行帶synchronized關鍵字的方法,哪個執行緒就持有該方法所屬物件的鎖Lock,而其他執行緒只能處於等待狀態;如果是多個執行緒訪問多個物件時,JVM會建立多個鎖。
2.1.4 synchronized方法與鎖物件
public class MyObject { public void methodA() { System.out.println(Thread.currentThread().getName()); try { Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
當將methodA方法加上synchronized時,執行緒排隊執行
對於共享資源的讀寫訪問才需要同步化
2.1.5 髒讀
髒讀:在讀取例項變數時此值已經被其他執行緒更改過了
解決方法:通過synchronized關鍵字解決