標籤:而且 cep xtend 實現 線程 存在 ted 出現 break
1.什麼是安全執行緒問題?
從某個線程開始訪問到訪問結束的整個過程,如果有一個訪問對象被其他線程修改,那麼對於當前線程而言就發生了安全執行緒問題;
如果在整個訪問過程中,無一對象被其他線程修改,就是安全執行緒的。
2.安全執行緒問題產生的根本原因
首先是多線程環境,即同時存在有多個操作者,單線程環境不存線上程安全問題。在單線程環境下,任何操作包括修改操作都是操作者自己發出的,
操作者發出操作時不僅有明確的目的,而且意識到操作的影響。
多個操作者(線程)必須操作同一個對象,只有多個操作者同時操作一個對象,行為的影響才能立即傳遞到其他動作者。
多個操作者(線程)對同一對象的操作必須包含修改操作,共同讀取不存線上程安全問題,因為對象不被修改,未發生變化,不能產生影響。
綜上可知,安全執行緒問題產生的根本原因是共用資料存在被並發修改的可能,即一個線程讀取時,允許另一個線程修改
看執行個體:類比火車站售票視窗,開啟三個視窗售票,總票數為100張
執行個體一:
package com.yyx.test;//類比火車站售票視窗,開啟三個視窗售票,總票數為100張//存線上程的安全問題class Window extends Thread { static int ticket = 100; public void run() { while (true) { if (ticket > 0) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "售票,票號為:" + ticket--); } else { break; } } }}public class TestWindow { public static void main(String[] args) { Window w1 = new Window(); Window w2 = new Window(); Window w3 = new Window(); w1.setName("視窗1"); w2.setName("視窗2"); w3.setName("視窗3"); w1.start(); w2.start(); w3.start(); }}
執行個體二:
package com.yyx.test;//使用實現Runnable介面的方式,售票/* * 此程式存線上程的安全問題:列印車票時,會出現重票、錯票 */class Window1 implements Runnable { int ticket = 100; public void run() { while (true) { if (ticket > 0) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "售票,票號為:" + ticket--); } else { break; } } }}public class TestWindow1 { public static void main(String[] args) { Window1 w = new Window1(); Thread t1 = new Thread(w); Thread t2 = new Thread(w); Thread t3 = new Thread(w); t1.setName("視窗1"); t2.setName("視窗2"); t3.setName("視窗3"); t1.start(); t2.start(); t3.start(); }}
3.安全執行緒的解決
必須讓一個線程操作共用資料完畢以後,其它線程才有機會參與共用資料的操作
1)線程的同步機制 synchronized
同步代碼塊
package com.yyx.test;/* 同步代碼塊 * synchronized(同步監視器){ * //需要被同步的代碼塊(即為操作共用資料的代碼) * } * 1.共用資料:多個線程共同操作的同一個資料(變數) * 2.同步監視器:由一個類的對象來充當。哪個線程擷取此監視器,誰就執行大括弧裡被同步的代碼。俗稱:鎖 * 要求:所有的線程必須共用同一把鎖! * 註:在實現的方式中,考慮同步的話,可以使用this來充當鎖。但是在繼承的方式中,慎用this! */class Window implements Runnable { int ticket = 50;// 共用資料 public void run() { while (true) { // this表示當前對象,本題中即為w synchronized (this) { if (ticket > 0) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "售票,票號為:" + ticket--); } } } }}public class TestWindow { public static void main(String[] args) { Window w = new Window(); Thread t1 = new Thread(w); Thread t2 = new Thread(w); Thread t3 = new Thread(w); t1.setName("視窗1"); t2.setName("視窗2"); t3.setName("視窗3"); t1.start(); t2.start(); t3.start(); }}
同步方法
package com.yyx.test;/* * 同步方法 * 將操作共用資料的方法聲明為synchronized。即此方法為同步方法,能夠保證當其中一個線程執行 * 此方法時,其它線程在外等待直至此線程執行完此方法 */class Window implements Runnable { int ticket = 50;// 共用資料 public void run() { while (true) { show(); } } public synchronized void show() { if (ticket > 0) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "售票,票號為:" + ticket--); } }}public class TestWindow { public static void main(String[] args) { Window w = new Window(); Thread t1 = new Thread(w); Thread t2 = new Thread(w); Thread t3 = new Thread(w); t1.setName("視窗1"); t2.setName("視窗2"); t3.setName("視窗3"); t1.start(); t2.start(); t3.start(); }}
Java多線程Thread安全執行緒