2 回答

TA貢獻1906條經(jīng)驗 獲得超10個贊
以下代碼證明您的類不是線程安全的。
它在兩個不同的線程中將 100000 個數(shù)字添加到列表中:
t1
使用putIfAbsent
你的類的方法t2
使用synchronized
塊正確鎖定synchronizedList
用于控制訪問的相同“互斥”對象,即包裝器列表本身。
由于兩種方法都試圖添加相同的100000 個對象,結(jié)果應(yīng)該是 100000 個對象的列表,即代碼應(yīng)該100000
在最后打印。
有時它確實如此,當(dāng)我運行它時,但大多數(shù)時候它比那個高一點,例如100075
,從而證明您putIfAbsent
的不是線程安全的。
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Test {
public static void main(String[] args) throws Exception {
ListHelper<Integer> helper = new ListHelper<>();
Thread t1 = new Thread(() -> Test.t1(helper));
Thread t2 = new Thread(() -> Test.t2(helper));
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(helper.list.size());
}
private static void t1(ListHelper<Integer> helper) {
for (int i = 0; i < 100000; i++)
helper.putIfAbsent(i);
}
private static void t2(ListHelper<Integer> helper) {
for (int i = 0; i < 100000; i++)
synchronized (helper.list) { // correct way to synchronize
if (! helper.list.contains(i))
helper.list.add(i);
}
}
}
class ListHelper <E> {
public List<E> list = Collections.synchronizedList(new ArrayList<E>());
public synchronized boolean putIfAbsent(E x) {
boolean absent = ! list.contains(x);
if (absent)
list.add(x);
return absent;
}
}

TA貢獻1805條經(jīng)驗 獲得超9個贊
通過確保在操作之間運行第二個線程,您可以表明您添加的第一個元素可能存在問題。
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ListHelper<E> {
public final List<E> list = Collections.synchronizedList(new ArrayList<E>());
public synchronized boolean putIfAbsent(E x) {
boolean absent = !list.contains(x);
runInANotherThread(() -> list.add(x));
if (absent)
list.add(x);
return absent;
}
public static void runInANotherThread(Runnable run) {
Thread t = new Thread(run);
t.start();
try {
t.join(1000);
} catch (InterruptedException ignored) {
}
}
public static void main(String[] args) {
ListHelper<Integer> list = new ListHelper<>();
list.putIfAbsent(1);
System.out.println(list.list);
}
}
印刷
[1, 1]
添加回答
舉報