例子程序:安全
/** * 多個線程一把鎖 * @author dev * */
public class MyThread extends Thread{ private int count = 5; //synchronized
@Override public void run() { count--; System.err.println(this.currentThread().getName() + " count = "+count); } public static void main(String[] args) { /** * 多個線程訪問myThread的run方法時,以排隊的方式進行處理(CPU分配的前後順序排隊) * 一個線程想要執行synchronized修飾的方法裏的代碼: * 1,嘗試得到鎖 * 2,若是拿到該鎖,執行synchronized代碼體內容,拿不到鎖,這個線程就會不斷嘗試得到這把鎖, * 直到拿到未止,並且是多個線程同時去競爭這把鎖(也就是有鎖競爭的問題) * */ MyThread myThread = new MyThread(); //參數:Runnable target, String name
Thread t1 = new Thread(myThread,"t1"); Thread t2 = new Thread(myThread,"t2"); Thread t3 = new Thread(myThread,"t3"); Thread t4 = new Thread(myThread,"t4"); Thread t5 = new Thread(myThread,"t5"); t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); } }
代碼說明:
MyThread繼承Thread,是一個線程類,有一成員變量count,重寫run方法:對count值進行減減,打印當前線程名字和count值。
main方法:啓動5個線程t一、t二、t三、t四、t5,把MyThread對象注入進去,啓動5個線程。
執行main方法,結果:
線程啓動後,5個線程都等待着cpu的執行,因此5個線程的執行順序是隨機的,致使看到的t一、t2 、t三、 t四、 t5的輸出順序是隨機的。對於count值,咱們內心預期的應該輸出 count=四、count=三、count=二、count=一、count=0,可是輸出結果跟心理預期的是不同的。這就是說,5個線程同時訪問MyThread類的run方法,對count值進行減減,不是線程安全的。多線程
將run方法加上synchronized 關鍵字,就是線程安全的:ide
//synchronized加鎖 @Override public synchronized void run() { count--; System.err.println(this.currentThread().getName() + " count = "+count); }
打印結果:this
這和咱們內心的預期是同樣的,也就是線程安全的。這就和開篇說的線程安全的定義:當多個線程訪問某一個類(對象或者方法)時,這個類始終都能表現出正確的行爲,那麼這個類(對象或方法)就是線程安全的。這裏的正確的行爲,就是指你內心預期的。spa
run方法 加上synchronized加鎖後,啓動5個線程,當第一個線程拿到鎖後,其餘4個線程就會等待,等着第一個線程釋放鎖,一次類推。線程
多線程就是一個廁所,廁所門上有一個鎖,外面5我的去搶這一把鎖,誰搶到了鎖,就能夠進去上廁所,當第一個進去的出來後,其餘4我的會同時去搶這把鎖。因此會產生鎖競爭的問題,當線程足夠多的時候,鎖競爭會致使CPU使用率太高,應儘可能避免鎖競爭。3d
搞10000個線程,看看鎖競爭cpu使用狀況:code
代碼:對象
MyThread myThread = new MyThread(); List<Thread> threads = new ArrayList<Thread>(); for(int i=0;i<10000;i++){ threads.add(new Thread(myThread,"t"+i)); } for(Thread t : threads){ t.start(); }
CPU:blog