如果多個線程同時運行同一個線程體,每次運行的結果可能都不一樣
class MyThread implements Runnable{int i = 10;public void run(){while(true){//獲取當前運行線程的名字System.out.PRintln(Thread.currentThread().getName() + i);i--;Thread.yield();if(i < 0){break;}}}}class Test{public static void main(String args[]){MyThread mt = new MyThread();//生成共用同一線程體的兩個線程對象Thread t1 = new Thread(mt);Thread t2 = new Thread(mt);//設置線程名字t1.setName("A線程:");t2.setName("B線程:");//分別啟動兩個線程t1.start();t2.start();}}
根據上圖我們知道結果明顯有錯誤,這就是多線程運行訪問同一份數據時出現的錯誤。錯誤原因:AB線程輪流運行,假設B線程先運行了幾行代碼后(打印B線程:10)輪到A線程運行。A線程運行線程體后也打印A線程:10
為解決這個問題,我們使用java關鍵字:synchronized
class MyThread implements Runnable{int i = 10;public void run(){while(true){//同步代碼塊synchronized(this){//獲取當前運行線程的名字System.out.println(Thread.currentThread().getName() + i);i--;Thread.yield();if(i < 0){break;}}}}}
使用同步代碼塊后,當A線程執行線程體時,獲得了對象鎖的使用權,即使A線程運行到yield方法時仍持有這個鎖的使用權,B線程沒有得到對象鎖的使用權,則需要等待A線程執行完線程體釋放對象鎖。當B線程獲得了對象鎖的使用權后A線程也需要等待。線程的同步是為了防止多個線程訪問同一數據時,對數據造成的破壞。
同步代碼塊鎖住的到底是什么呢?
class Service{public void fun1(){synchronized(this){try{Thread.sleep(3000);}catch(Exception e){System.out.println(e);}System.out.println("fun1");}}public void fun2(){synchronized(this){System.out.println("fun2");}}}class MyThread1 implements Runnable{private Service service;public MyThread1(Service service){this.service = service;}public void run(){service.fun1();}}class MyThread2 implements Runnable{private Service service;public MyThread2(Service service){this.service = service;}public void run(){service.fun2();}}class Test{public static void main(String args[]){Service service = new Service();Thread t1 = new Thread(new MyThread1(service));Thread t2 = new Thread(new MyThread2(service));t1.start();t2.start();}}啟動t1線程后,t1線程調用fun1方法,執行同步代碼塊休眠3秒鐘,并持有對象鎖。如果沒有同步代碼塊,t1線程休眠則執行t2線程,但因為fun2方法的同步代碼塊的對象鎖也是this,所以t2線程無法執行,需要等待t1線程釋放對象鎖。由此可見,synchronized鎖住的是對象而不是代碼塊,一旦某一線程獲得了某個對象的對象鎖,那么這個對象的所有同步代碼塊其他線程都不能執行,需要等待對象鎖的釋放。
Synchronized除了用于同步代碼塊,還可用于同步方法,如
public synchronized void fun2(){System.out.println("fun2");}同步方法和同步代碼塊功能類似,但同步方法鎖住的是this對象,同步代碼塊可以鎖定除了this之外的指定對象。當一個線程調用對象的其中一個同步方法時,那么這個對象的其他同步方法也不能被其他線程使用。
新聞熱點
疑難解答