【发布时间】:2014-06-14 19:13:37
【问题描述】:
当运行多个线程时,我读到交错成为一个问题,其中一个线程不考虑另一个线程对对象的更改。 Jave 提供了同步方法、同步状态、Lock 对象和新的 Concurrency 类对象,以确保在多个线程影响单个对象时,在其他线程影响对象字段之前,每个线程都可以独占轮到影响对象字段。
现在,虽然这很清楚,但当您不使用单个对象而是使用多个线程处理 MULTIPLE 对象时,它对我来说有点灰暗。所以我试着测试一下。我有一个 ExecuterService 有 50 个线程。它产生了一个新的 Responder 线程(它本身就是一个 NEW OBJECT):
ExecutorService executor=Executors.newFixedThreadPool(50);
for(int i=0;i<50;i++){
executor.execute(new Responder());
}
因为每个线程本身都是一个实例化的对象,如果我的 Responder 类看起来像这样:
public class Responder implements Runnable {
private ArrayList<Integer> list=new ArrayList<Integer>();
private Random random = new Random();
@Override
public void run() {
for(int i=0;i<1000;i++){
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
list.add(random.nextInt(100));
}
System.out.println("The list size: " + list.size());
}
}
是否每个线程都使用自己的 Responder 实例,这样线程安全就不是问题了?比如,ArrayList list 是不是线程间共享数据?我的直觉说线程安全在这里不是问题,因为每个线程都使用自己的实例、自己的成员而不是共享数据,当我尝试运行这个示例时,size() 调用输出相同的 (1000)所有的线程。所以看起来它是线程安全的,但我尝试了一种所谓的非线程安全方式:
public static void main(String[] args) {
int i;
//checking if instantiating new object into executor is thread safe
ExecutorService executor=Executors.newFixedThreadPool(50);
for(i=0;i<50;i++){
executor.execute(new Responder());
}
// checking that running multiple threads with shared object is not thread safe
UnsafeResponder unsafeResp = new UnsafeResponder();
unsafeResp.execute();
}
public class UnsafeResponder {
private ArrayList<Integer> list=new ArrayList<Integer>();
private Random random = new Random();
private void processData(){
for(int i=0;i<1000;i++){
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
list.add(random.nextInt(100));
}
}
public void execute(){
Thread t1 = new Thread(new Runnable(){
public void run() {
processData();
}
});
Thread t2 = new Thread(new Runnable(){
public void run() {
processData();
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//print out value of shared data
System.out.println("The list size of shared data: " + list.size());
}
}
即使我没有使用锁或同步语句,每次我调用它时,这种非线程安全方式都会正确打印出 2000。这就是为什么我什至不能 100% 确定我的初始示例是否存在线程安全问题,因为我似乎无法生成线程不安全的等价物。
【问题讨论】:
-
@user2864740 你能改写一下吗?我不确定“executor.execute(new Responder());”是如何导致共享可变状态的。
-
@user2864740 所以当我运行“executor.execute(new Responder());”时,这意味着每个 Responder 都在使用自己的数据,因此线程安全不会有问题,对吗?
-
@user2864740 我刚刚阅读了您编辑的评论。所以您说第一个示例没有线程安全问题,因为每个线程都处理自己的对象,而第二个示例可能存在线程安全问题,因为它们具有共享的可变状态。出于好奇,我将第二个示例运行了 50 次,它总是给我正确的值,如果它被破坏了就不应该是这种情况。
标签: java multithreading