1 java multithreading thread-safety
我最近读了一本书"Java Concurrency in Practice 2nd",作者提到如果我们使用Collections.synchronizedList来创建一个安全的线程List,那么我们必须确保我们使用的是来自SynchronizedCollection的同一个锁.下面的代码来自这本书:
public 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;
}
}
Run Code Online (Sandbox Code Playgroud)
在这个类中,方法putIfAbsent已被ListHelper中的Object锁定,但是list.contains不使用此Object作为锁,有两个锁,因此在多线程下它不安全.但我的问题是如何证明它不是线程安全的.你有什么想法?
以下代码证明您的类不是线程安全的.
它在两个不同的线程中将100000个数字添加到列表中:
t1使用putIfAbsent你的类的方法t2使用synchronized块来正确锁定synchronizedList用于控制访问的相同"互斥"对象,即包装器列表本身.由于两种方法都试图添加相同的 100000个对象,因此结果应该是100000个对象的列表,即代码应该100000在末尾打印.
有时它确实如此,当我运行它时,但大部分时间它都比它高一点,例如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;
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
70 次 |
| 最近记录: |