很多同窗在學習Java中的多線程這一章時,都會以爲腦子很亂,以爲這一章的知識點太難以理解。特別是對於其中線程同步(synchronized)更是迷茫。本文試圖以淺顯的例子來跟你們共同分享學習心得。 java
先看一個例子 多線程
package com.chinasofti.thread; 學習
publicclass MyThread implements Runnable{ 測試
privateinta = 1; spa
publicsynchronizedvoid f1(){ 線程
System.out.println("a = " + a); 對象
try { 接口
Thread.sleep(1000); 同步
} catch (InterruptedException e) { io
// TODO Auto-generated
catch block
e.printStackTrace();
}
System.out.println("a = " + a);
}
publicvoid f2(){
a++;
}
publicvoid run() {
f1();
}
publicstaticvoid main(String[] args) {
MyThread myThread = newMyThread();
Thread t1 = newThread(myThread);
t1.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated
catch block
e.printStackTrace();
}
myThread.f2();
}
}
例子說明:咱們自定義了一個MyThread類,該類實現了java.lang.Runnable接口。類中包含一個靜態私有變量a=1;提供了一個同步方法f1,該方法的做用是先打印a,而後執行該方法的線程休眠1000毫秒,再次打印a;提供了一個非同步方法f2,該方法做用是使a自加1;實現java.lang.Runnable接口的run方法,該方法執行f1()。
程序啓動時,首先啓動主線程執行main方法。在main方法中,先new一個MyThread類對象myThread,再利用該對象建立一條線程t1,調用其start()方法啓動線程,主線程休眠100毫秒的做用是使得t1在主線程休眠期間獲得CPU執行權,執行到f1()方法中的Thread.sleep(1000)處。在t1線程休眠1000毫秒時,主線程繼續執行MyThread.f2()。該測試程序的最終結果是打印a=1 a=2。也就是說在t1線程執行同步方法f1並休眠1000毫秒的空當裏,主線程執行了myThread對象的非同步方法f2(),修改了a的值。t1線程從休眠中恢復過來再次打印a的值已經變成了2。
也許有同窗看到這裏就有疑問了:「咱們不是說synchronized的意思是得到對象鎖嗎?那麼t1線程執行了同步方法f1(),那就應該得到myThread對象的對象鎖啊,怎麼在它休眠期間另外一條線程主線程也可以執行myThread對象的f2()方法呢?難道是由於t1線程休眠了以後就釋放掉對象鎖了嗎?」
對於這個問題的解釋是這樣,t1線程執行run()方法,run()方法調用同步方法f1(),則此時t1線程擁有了myThread這個對象的對象鎖,接下來執行Thread.sleep(long miliseconds)這個方法,則線程(即t1)進入休眠狀態,可是Thread.sleep(long miliseconds)的執行不會致使線程釋放掉對象鎖。而main線程之因此可以在t1線程休眠以後繼續執行myThread.f2(),是由於f2()並非同步方法。咱們一般說「得到對象鎖」,實際上更確切直白的含義是「獨佔該對象的同步方法和同步代碼塊」。可是對於非同步方法,對象鎖是不起做用的。
咱們能夠將例子作以下改動:將f2()修改成同步方法,其餘不變。你們有興趣試一下會發現此時的程序執行結果變成了打印a=1 a=1。由於此時f2()爲同步方法,t1線程在休眠期間並無釋放對象鎖,即此時t1線程「獨佔myThread對象的f1(),f2()方法」。所以此時主線程不可能執行myThread.f2()。只有當t1線程執行完了f1()方法以後,即兩次打印a=1 a=1,釋放掉對象鎖,此時主線程才能繼續執行myThread的同步方法f2()。
不少同窗在理解「同步」這個概念時錯誤地將其理解成爲「並行」,從而獲得一些混亂的結論,最後變得愈來愈茫然。而經過上面的例子咱們能夠看到,其實線程中「同步」的概念更接近於「串行」。即「同一時刻只能有一條線程擁有一個對象的對象鎖,在該線程獨佔該對象的同步方法和同步代碼塊時,其餘線程不能訪問該對象的同步方法和同步代碼塊」。而synchronized關鍵字的做用是聲明同步方法或者同步代碼塊,執行到這兒的線程能夠告訴其餘線程說:「嘿,如今這個對象的同步方法和代碼塊我佔了,大家先等着別搶,我用完了大家才能接着用!」。