Java線程學(xué)習(xí)(2):關(guān)鍵字synchronized
有了synchronized關(guān)鍵字,多線程程序的運(yùn)行結(jié)果將變得可以控制。synchronized關(guān)鍵字用于保護(hù)共享數(shù)據(jù)。請大家注意"共享數(shù)據(jù)",
你一定要分清哪些數(shù)據(jù)是共享數(shù)據(jù),JAVA是面向?qū)ο蟮某绦蛟O(shè)計(jì)語言,所以初學(xué)者在編寫多線程程序時(shí),容易分不清哪些數(shù)據(jù)是共享數(shù)據(jù)。請看下面的例子:
實(shí)例一:
實(shí)例二:
t1_name:forloop:1
t1_name:forloop:2
t2_name:forloop:0
t1_name:forloop:3
t2_name:forloop:1
t1_name:forloop:4
t2_name:forloop:2
t1_name:synchronizedforloop:0
t2_name:forloop:3
t1_name:synchronizedforloop:1
t2_name:forloop:4
t1_name:synchronizedforloop:2
t1_name:synchronizedforloop:3
t1_name:synchronizedforloop:4
t2_name:synchronizedforloop:0
t2_name:synchronizedforloop:1
t2_name:synchronizedforloop:2
t2_name:synchronizedforloop:3
t2_name:synchronizedforloop:4
第一個(gè)for循環(huán)沒有受synchronized保護(hù)。對于第一個(gè)for循環(huán),t1,t2可以同時(shí)訪問。運(yùn)行結(jié)果
表明t1執(zhí)行到了k=2 時(shí),t2開始執(zhí)行了。t1首先執(zhí)行完了第一個(gè)for循環(huán),此時(shí)還沒有執(zhí)行完第一個(gè)
for循環(huán)(t2剛執(zhí)行到k=2)。t1開始執(zhí)行第二個(gè)for循環(huán),當(dāng) t1的第二個(gè)for循環(huán)執(zhí)行到k=1時(shí),t2
的第一個(gè)for循環(huán)執(zhí)行完了。http://bianceng.cn(編程入門)
t2想開始執(zhí)行第二個(gè)for循環(huán),但由于t1首先執(zhí)行了第二個(gè)for循環(huán),這個(gè)對象的鎖標(biāo)志自然在
t1手中(synchronized方法的執(zhí)行權(quán)也就落到了t1手中),在t1沒執(zhí)行完第二個(gè)for循環(huán)的時(shí)候,它
是不會(huì)釋放鎖標(biāo)志的。
所以t2必須等到t1執(zhí)行完第二個(gè)for循環(huán)后,它才可以執(zhí)行第二個(gè)for循環(huán)
實(shí)例一:
public class FirstThread implements Runnable{
public synchronized void run(){
for(int i=1;i<10;i++){
System.out.println(""+i);
}
}
public FirstThread(){
}
public static void main(String[] args){
Runnable r1=new FirstThread();
Runnable r2=new FirstThread();
Thread t1=new Thread(r1);
Thread t2=new Thread(r2);
t1.start();
t2.start();
}
}
在這個(gè)程序中,run()被加上了synchronized關(guān)鍵字。在main方法中創(chuàng)建了兩個(gè)線程。你可能會(huì)認(rèn)為此程序的運(yùn)行結(jié)果一定為:0123456789 0123456789。答案不是這樣子的,這個(gè)程序中synchronized關(guān)鍵字保護(hù)的不是共享數(shù)據(jù)(其實(shí)在這個(gè)程序中synchronized關(guān)
鍵字沒有起到任何作用,此程序的運(yùn)行結(jié)果是不可預(yù)先確定的)。這個(gè)程序中的t1,t2是兩個(gè)對象(r1,r2)的線程。JAVA是面向?qū)ο蟮某绦蛟O(shè)計(jì)語
言,不同的對象的數(shù)據(jù)是不同的,r1,r2有各自的run()方法,而synchronized使同一個(gè)對象的多個(gè)線程,在某個(gè)時(shí)刻只有其中的一個(gè)線程可
以訪問這個(gè)對象的synchronized數(shù)據(jù)。每個(gè)對象都有一個(gè)"鎖標(biāo)志",當(dāng)這個(gè)對象的一個(gè)線程訪問這個(gè)對象的某個(gè)synchronized數(shù)據(jù)時(shí),
這個(gè)對象的所有被synchronized修飾的數(shù)據(jù)將被上鎖(因?yàn)?鎖標(biāo)志"被當(dāng)前線程拿走了),只有當(dāng)前線程訪問完它要訪問的
synchronized數(shù)據(jù)時(shí),當(dāng)前線程才會(huì)釋放"鎖標(biāo)志",這樣同一個(gè)對象的其它線程才有機(jī)會(huì)訪問synchronized數(shù)據(jù)。public synchronized void run(){
for(int i=1;i<10;i++){
System.out.println(""+i);
}
}
public FirstThread(){
}
public static void main(String[] args){
Runnable r1=new FirstThread();
Runnable r2=new FirstThread();
Thread t1=new Thread(r1);
Thread t2=new Thread(r2);
t1.start();
t2.start();
}
}
實(shí)例二:
public class SecondThread implements Runnable{
public synchronized void run(){
for(int i=1;i<10;i++){
System.out.println(""+i);
}
}
public SecondThread(){
}
public static void main(String[] args){
Runnable r=new SecondThread();
//Runnable r2=new FirstThread();
Thread t1=new Thread(r);
Thread t2=new Thread(r);
t1.start();
t2.start();
}
}
public synchronized void run(){
for(int i=1;i<10;i++){
System.out.println(""+i);
}
}
public SecondThread(){
}
public static void main(String[] args){
Runnable r=new SecondThread();
//Runnable r2=new FirstThread();
Thread t1=new Thread(r);
Thread t2=new Thread(r);
t1.start();
t2.start();
}
}
如果你運(yùn)行1000次這個(gè)程序,它的輸出結(jié)果也一定每次都是:01234567890123456789。因?yàn)檫@里的synchronized保護(hù)的是共享數(shù)據(jù)。t1,t2是同一個(gè)對象(r)的兩個(gè)線程,當(dāng)其中的一個(gè)線程(例如:t1)開始執(zhí)行run()方法時(shí),由于run()受 synchronized保護(hù),所以同一個(gè)對象的其他線程(t2)無法訪問synchronized方法(run方法)。只有當(dāng)t1執(zhí)行完后t2才有機(jī)會(huì) 執(zhí)行。
實(shí)例三:
public class ThreeThread implements Runnable{
public void run(){
synchronized(this){
for(int i=1;i<10;i++){
System.out.println(""+i);
}}
}
public ThreeThread(){
}
public static void main(String[] args){
Runnable r=new SecondThree();
//Runnable r2=new FirstThread();
Thread t1=new Thread(r);
Thread t2=new Thread(r);
t1.start();
t2.start();
}
}
public void run(){
synchronized(this){
for(int i=1;i<10;i++){
System.out.println(""+i);
}}
}
public ThreeThread(){
}
public static void main(String[] args){
Runnable r=new SecondThree();
//Runnable r2=new FirstThread();
Thread t1=new Thread(r);
Thread t2=new Thread(r);
t1.start();
t2.start();
}
}
這個(gè)程序與示例2的運(yùn)行結(jié)果一樣。在可能的情況下,應(yīng)該把保護(hù)范圍縮到最小,可以用示例3的形式,this代表"這個(gè)對象"。沒有必要把整個(gè)run()保護(hù)起來,run()中的代碼只有一個(gè)for循環(huán),所以只要保護(hù)for循環(huán)就可以了。
實(shí)例四:public class FourThread implements Runnable{
public void run(){
for(int i=1;i<10;i++){
System.out.println(Thread.currentThread().getName()+"forloop"+i);
}
synchronized(this){
for(int i=1;i<10;i++){
System.out.println(Thread.currentThread().getName()+"synchronized"+i);
}}
}
public SecondThread(){
}
public static void main(String[] args){
Runnable r=new ThreeThread();
//Runnable r2=new FirstThread();
Thread t1=new Thread(r);
Thread t2=new Thread(r);
t1.start();
t2.start();
}
}
t1_name:forloop:0public void run(){
for(int i=1;i<10;i++){
System.out.println(Thread.currentThread().getName()+"forloop"+i);
}
synchronized(this){
for(int i=1;i<10;i++){
System.out.println(Thread.currentThread().getName()+"synchronized"+i);
}}
}
public SecondThread(){
}
public static void main(String[] args){
Runnable r=new ThreeThread();
//Runnable r2=new FirstThread();
Thread t1=new Thread(r);
Thread t2=new Thread(r);
t1.start();
t2.start();
}
}
t1_name:forloop:1
t1_name:forloop:2
t2_name:forloop:0
t1_name:forloop:3
t2_name:forloop:1
t1_name:forloop:4
t2_name:forloop:2
t1_name:synchronizedforloop:0
t2_name:forloop:3
t1_name:synchronizedforloop:1
t2_name:forloop:4
t1_name:synchronizedforloop:2
t1_name:synchronizedforloop:3
t1_name:synchronizedforloop:4
t2_name:synchronizedforloop:0
t2_name:synchronizedforloop:1
t2_name:synchronizedforloop:2
t2_name:synchronizedforloop:3
t2_name:synchronizedforloop:4
第一個(gè)for循環(huán)沒有受synchronized保護(hù)。對于第一個(gè)for循環(huán),t1,t2可以同時(shí)訪問。運(yùn)行結(jié)果
表明t1執(zhí)行到了k=2 時(shí),t2開始執(zhí)行了。t1首先執(zhí)行完了第一個(gè)for循環(huán),此時(shí)還沒有執(zhí)行完第一個(gè)
for循環(huán)(t2剛執(zhí)行到k=2)。t1開始執(zhí)行第二個(gè)for循環(huán),當(dāng) t1的第二個(gè)for循環(huán)執(zhí)行到k=1時(shí),t2
的第一個(gè)for循環(huán)執(zhí)行完了。http://bianceng.cn(編程入門)
t2想開始執(zhí)行第二個(gè)for循環(huán),但由于t1首先執(zhí)行了第二個(gè)for循環(huán),這個(gè)對象的鎖標(biāo)志自然在
t1手中(synchronized方法的執(zhí)行權(quán)也就落到了t1手中),在t1沒執(zhí)行完第二個(gè)for循環(huán)的時(shí)候,它
是不會(huì)釋放鎖標(biāo)志的。
所以t2必須等到t1執(zhí)行完第二個(gè)for循環(huán)后,它才可以執(zhí)行第二個(gè)for循環(huán)
posted on 2009-02-26 19:43 草原上的駱駝 閱讀(415) 評論(0) 編輯 收藏 所屬分類: JAVA基礎(chǔ)知識