您好,登錄后才能下訂單哦!
本篇內(nèi)容主要講解“Java線程不同步的現(xiàn)象怎么解決”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Java線程不同步的現(xiàn)象怎么解決”吧!
線程的安排畢竟是隨機的,很少會有不同步的出現(xiàn),次數(shù)少了不容易發(fā)現(xiàn)。
我常用的方法是,先讓無限循環(huán)開始,循環(huán)的時候也不要求輸出什么的,只加上一個停止的條件,比如:
if (counter1 != counter2)
{
System.out.println(counter1 + " ," + counter2)
System.exit(0);
}
剩下的就是等了,一般十幾秒甚至幾秒就出結(jié)果了,可以發(fā)現(xiàn)記數(shù)已經(jīng)到幾十萬或者幾百萬了。
如果同時開了5個線程,等了一分鐘,我就算是它同步了。
我的方法可能不太科學,不過效果挺好。
將下面的代碼直接拷貝就可以了,程序名為Sharing2.java,版本是1.4.1
class TwoCounter extends Thread {
private int count1 = 0, count2 = 0;
private boolean started=false;
public void start(){
if (!started)
{
started=true;
super.start();
}
}
public void run() {
while (true) {
count1++;
count2++;
// System.out.println("Count1="+count1+",Count2="+count2);
try {
sleep(500);
} catch (InterruptedException e){System.out.println("TwoCounter.run");}
}
}
public void synchTest() {
// Sharing2.incrementAccess();
if(count1 != count2)
{System.out.println(count1+","+count2);
System.exit(0);
}
}
}
class Watcher extends Thread {
private Sharing2 p;
public Watcher(Sharing2 p) {
this.p = p;
start();
}
public void run() {
while(true) {
p.s.synchTest();
try {
sleep(500);
} catch (InterruptedException e){System.out.println("Watcher.run");}
}
}
}
public class Sharing2 {
TwoCounter s;
private static int accesSCOunt = 0;
public static void incrementAccess() {
// accessCount++;
// System.out.println("accessCount="+accessCount);
}
public static void main(String[] args) {
Sharing2 aaa = new Sharing2();
aaa.s=new TwoCounter();
aaa.s.start();
new Watcher(aaa);
}
} ///:~
另外,根據(jù)你的意思,我的程序是沒有問題的,只是線程少了,不同步很難產(chǎn)生,要等到counter增加到很大數(shù)目的時候才有可能,對嗎?
我是這樣想的:不同步而發(fā)生沖突是一種可能性,而sychronize是讓這種可能性為0。你沒有1發(fā)現(xiàn)不同步,并不能證明永遠都不會發(fā)生不同步的情況,那只是一個時間問題。系統(tǒng)對線程的調(diào)度受了環(huán)境的影響,要是你機器上同時還跑了很多程序,可能情況就不同了。
呵呵,我用tianfeichen(側(cè)耳傾聽)的方法運行的程序,也就是我上面貼的代碼居然有結(jié)果了,counter1= 217327,counter2=217356,還真想差的不少。但是時間上絕不是一兩分鐘那么簡單,至少過了兩個小時,可能真是我和他的運行環(huán)境的不同造成的.正如hey_you(Hey)所說,只是一個時間問題.
我考,一兩個小時你也能堅持,服了。
我認為問題結(jié)果也就兩點了。一個就是我認為的線程數(shù)量
另一個就是你認為的setText會有比較多的處理,占用比較多的資源。
兩種情況都會影響到這個問題的出現(xiàn)幾率:)樓主宰總結(jié)一下吧,呵呵。
sleep(500)占用的時間勝過for(5000)的時間,因此線程在sleep中被切換的概率遠勝于在for中被中斷的概率?。。ɑ仡^去看我的程序就知道了)
事實上,兩個變量從不相等變?yōu)橄嗟龋钦f明了不同步??!
順便說一下關(guān)于swing和awt控件在線程中操作時,比如setText,常造成很多意外
我將各位的觀點綜合起來總結(jié)一下:
首先要肯定的是,假如不使用synchronized關(guān)鍵字來定義同步方法或者定義同步塊,那么,發(fā)生不同步的可能是絕對存在的,反過來說,synchronized就是讓這種可能性為0.
在第一種情況下,發(fā)生不同步的可能雖然存在,但是它的幾率受到以下幾個方面因素的影響
1.在不同的操作系統(tǒng)及運行環(huán)境下,捕捉到不同步的幾率可能就不一樣,或者說等待的時間可能就有長有短
2.程序中線程數(shù)目的多寡,如果線程太少,那么這種不同步就難于捕捉到,可能需要等待很長的時間
3.代碼本身的影響.比如使用awt類中涉及到GUI的方法,可能就會占用較多的資源,造成很多意外,那么發(fā)生沖突的可能性就大得多
4.線程是由操作系統(tǒng)隨機分配的,本來就存在著不確定性,這種不確定性也會影響最后的結(jié)果
不知道是否正確,大家還有什么補充呢?
明天正式結(jié)帖
不過說實話,我有點搞不懂,為什么最后的結(jié)果,counter1(217327)和counter2(217356)會相差那么多呢.按照我的程序,即便watcher線程插到兩個自加的語句中間來,檢測到的這兩個計數(shù)器之間的差異頂多也就是1啊.出現(xiàn)這么大的差異,只可能是某一個計數(shù)器的自加語句有好多次在根本沒有運行的情況下就被強行中斷了.這就太恐怖了!雖然有其它線程的存在會干擾當前線程,但是也不至于讓當前線程語句不運行吧,最多也就是等等再運行啊?我有點糊涂了,操作系統(tǒng)沒學好,如果大家不嫌麻煩,清幫我解釋一下吧
結(jié)果現(xiàn)在又有新的問題,我想又要等到明天才有答案吧
但我們今天可以解決另一個涉及到synchronized的問題.這是我在論壇上看到的一個貼子.正是因為我解決不了,我才認為有必要回頭來好好研究線程和同步等內(nèi)容的.
問題如下:
file://分析這段程序,并解釋一下,著重講講synchronized、wait(),notify 謝謝!
class ThreadA
{
public static void main(String[] args)
{
Threadb b=new ThreadB();
b.start();
System.out.println("b is start....");
synchronized(b)//括號里的b是什么意思,起什么作用?
{
try
{
System.out.println("Waiting for b to complete...");
b.wait();//這一句是什么意思,究竟讓誰wait?
System.out.println("Completed.Now back to main thread");
}catch (InterruptedException e){}
}
System.out.println("Total is :"+b.total);
}
}
class ThreadB extends Thread
{
int total;
public void run()
{
synchronized(this)
{
System.out.println("ThreadB is running..");
for (int i=0;i<100;i++ )
{
total +=i;
System.out.println("total is "+total);
}
notify();
}
}
}
要分析這個程序,首先要理解notify()和wait(),為什么在前幾天紀錄線程的時候沒有紀錄這兩個方法呢,因為這兩個方法本來就不屬于Thread類,而是屬于最底層的object基礎(chǔ)類的,也就是說不光是Thread,每個對象都有notify和wait的功能,為什么?因為他們是用來操縱鎖的,而每個對象都有鎖,鎖是每個對象的基礎(chǔ),既然鎖是基礎(chǔ)的,那么操縱鎖的方法當然也是最基礎(chǔ)了.
再往下看之前呢,首先最好復習一下Think in Java的14.3.1中第3部分內(nèi)容:等待和通知,也就是wait()和notify了.
按照Think in Java中的解釋:"wait()允許我們將線程置入“睡眠”狀態(tài),同時又“積極”地等待條件發(fā)生改變.而且只有在一個notify()或notifyAll()發(fā)生變化的時候,線程才會被喚醒,并檢查條件是否有變."
我們來解釋一下這句話.
"wait()允許我們將線程置入“睡眠”狀態(tài)",也就是說,wait也是讓當前線程阻塞的,這一點和sleep或者suspend是相同的.那和sleep,suspend有什么區(qū)別呢?
區(qū)別在于"(wait)同時又“積極”地等待條件發(fā)生改變",這一點很關(guān)鍵,sleep和suspend無法做到.因為我們有時候需要通過同步(synchronized)的幫助來防止線程之間的沖突,而一旦使用同步,就要鎖定對象,也就是獲取對象鎖,其它要使用該對象鎖的線程都只能排隊等著,等到同步方法或者同步塊里的程序全部運行完才有機會.在同步方法和同步塊中,無論sleep()還是suspend()都不可能自己被調(diào)用的時候解除鎖定,他們都霸占著正在使用的對象鎖不放.
而wait卻可以,它可以讓同步方法或者同步塊暫時放棄對象鎖,而將它暫時讓給其它需要對象鎖的人(這里應(yīng)該是程序塊,或線程)用,這意味著可在執(zhí)行wait()期間調(diào)用線程對象中的其他同步方法!在其它情況下(sleep啊,suspend啊),這是不可能的.
但是注意我前面說的,只是暫時放棄對象鎖,暫時給其它線程使用,我wait所在的線程還是要把這個對象鎖收回來的呀.wait什么?就是wait別人用完了還給我?。?br/> 好,那怎么把對象鎖收回來呢?
第一種方法,限定借出去的時間.在wait()中設(shè)置參數(shù),比如wait(1000),以毫秒為單位,就表明我只借出去1秒中,一秒鐘之后,我自動收回.
第二種方法,讓借出去的人通知我,他用完了,要還給我了.這時,我馬上就收回來.哎,假如我設(shè)了1小時之后收回,別人只用了半小時就完了,那怎么辦呢?靠!當然用完了就收回了,還管我設(shè)的是多長時間啊.
那么別人怎么通知我呢?相信大家都可以想到了,notify(),這就是最后一句話"而且只有在一個notify()或notifyAll()發(fā)生變化的時候,線程才會被喚醒"的意思了.
因此,我們可將一個wait()和notify()置入任何同步方法或同步塊內(nèi)部,無論在那個類里是否準備進行涉及線程的處理。而且實際上,我們也只能在同步方法或者同步塊里面調(diào)用wait()和notify().
這個時候我們來解釋上面的程序,簡直是易如反掌了.
synchronized(b){...};的意思是定義一個同步塊,使用b作為資源鎖。b.wait();的意思是臨時釋放鎖,并阻塞當前線程,好讓其他使用同一把鎖的線程有機會執(zhí)行,在這里要用同一把鎖的就是b線程本身.這個線程在執(zhí)行到一定地方后用notify()通知wait的線程,鎖已經(jīng)用完,待notify()所在的同步塊運行完之后,wait所在的線程就可以繼續(xù)執(zhí)行.
到此,相信大家對“Java線程不同步的現(xiàn)象怎么解決”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學習!
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。