我很困惑,為什么我在同步或鎖定方法中做'i '時得到一個隨機的結果?
public class aaa implements Runnable {
static int count = 0;
public static void main(String[] args) {
aaa aaa = new aaa()。
aaa.create()。
}
public void create() {
ExecutorService executor = Executors.newFixedThreadPool(100)。
for (int i = 0; i < 1000; i ) {
aaa thread = new aaa()。
executor.execute(thread)。
}
executor.shutdown()。
while(true){
if(executor.isTerminated()){
System.out.println("a"/span> count)。
break。
}
}
}
@Override; }
public void run() {
this.test()。
}
public void test() {
Lock lock = new ReentrantLock()。
try {
lock.lock();
count ;
System.out.println(count)。
} finally {
lock.unlock()。
}
}
}
或者:
public synchronized void test {
count 。
System.out.println(count)。
}
結果是一個亂數,有時是1000,有時是998,999......等等,而且'test'方法里面的列印結果不是一個序列,它是這樣的:
867
836
825 836
824 825
821[/span
820
819
817 819
816 817
a 999 999
但是,如果它在一個同步塊中,一切看起來都很好:
public void test(){
synchronized (aaa.class) {
count 。
System.out.println(count)。
}
結果:
993
994
995 995
996
997
998 998
999 999
1000 1000
a1000
我認為上面所有的方法都應該給我相同的結果1000,而且自增量應該是一個序列,但是只有最后一個方法可以作業。代碼有什么問題嗎?請幫助!
uj5u.com熱心網友回復:
你正在創建aaa的多個實體,每個實體都創建了自己的ReentrantLock,執行中的每個執行緒都順利地從自己的實體中獲得了鎖。
public void test() {
Lock lock = new ReentrantLock()。
try {
lock.lock();
count ;
System.out.println(count)。
} finally {
lock.unlock()。
}
}
由于aaa有多個實體,每個執行緒都在自己的實體上運行,同步方法使用aaa.class的當前物件
public synchronized void test() {
count 。
System.out.println(count)。
}
在這種方法中得到正確結果的原因是,你把aaa.class作為同步的物件
。public void test() {
synchronized (aaa.class) {
count 。
System.out.println(count)。
}
解決方案是,在所有執行緒中重復使用同一個鎖(ReentrantLock)。將鎖定義在與變數count相同的級別上將會解決這個問題。
uj5u.com熱心網友回復:
你必須創建一個單一的mutex,即:
你必須創建一個單一的mutex。
static Lock lock = new ReentrantLock() 。
你的同步方法不起作用,因為你正在創建N aaa實體,那么,每個(非靜態)方法都是不同的(有自己的mutex)。
你的synchronized (aaa.class)作業,因為aaa.class對于所有aaa實體和方法都是相同的Object。
那么,如果你需要同步方法,請確保它對所有執行緒都是一樣的,例如,如果test是static,那么它對所有執行緒都是一樣的
@Override
public void run() {
test()。
}
public static synchronized void test() {
count ;
}
但你可以注入一個"計數器類",例如
class Counter {
int count = 0;
//非靜態的,但對所有的人來說是同步的(因為他們使用同一個`counter`物件)。
synchronized void inc() {
count ;
}
}
將用于所有執行緒
...
SyncTest thread = new SyncTest( counter)。//<==相同
...
(完整代碼)
public class SyncTest implements Runnable {
private final Counter c。
public SyncTest(Counter c) {
this.c = c;
}
static class Counter {
int count = 0。
//非靜態的,但對所有的人來說是同步的(因為他們使用同一個`counter`物件)。
synchronized void inc() {
count ;
}
}
@Override
public void run() {
test()。
}
public void test() {
this.c.inc()。
}
public static void main(String[] args) {
//一個計數器用于所有 (String[] args)
Counter counter = new Counter() 。
ExecutorService executor = Executors.newFixedThreadPool(100)。
for (int i = 0; i < 10000; i ) {
SyncTest thread = new SyncTest(counter)。
executeor.execute(thread)。
}
executor.shutdown()。
while (true) {
if (executor.isTerminated() ) {
System.out.println("a" counter.count)。
break。
}
}
}
uj5u.com熱心網友回復:
經驗法則。在你想用它來保護的變數之后的下一行宣布你的鎖定變數,并使用相同的關鍵字來宣布它。 例如,
public class aaa implements Runnable {
static int count = 0;
static Lock countLock = new ReentrantLock() 。
...
如果你對這里的其他答案有足夠深入的閱讀,那么你就會明白為什么這樣做有幫助。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/325308.html
標籤:
