我有两节课
classA {
private ArrayList<String> list = new ArrayList();
void addString(String s){
list.add(s);
}
void start(){
new ClassB(list).start();
}
}
classB extends Thread{
ArrayList<String> s;
public ClassB(ArrayList<String> s) { this.s = s; }
void run(){
for (String s1 : s){
// print s1
}
}
}
现在当我把代码写成
ClassA A = new ClassA();
A.addString("1");
A.addString("2");
A.addString("3");
A.start();
我希望classb中的run()打印列表中的所有元素。i、 e(1,2,3)。
这总是默认的还是我们需要应用多线程概念来实现它?
如果列表是非易失性的呢?新线程是否可以看到所有元素(1、2、3)
如果我在a.start()之后添加另一个元素(比如a.addstring(“4”),那么我应该怎么做才能让新线程打印所有4个元素呢?
1条答案
按热度按时间gk7wooem1#
如果在启动另一个线程(classb)之前添加所有元素,则是安全的。jls公司§17.4.4说:
启动线程的操作与它启动的线程中的第一个操作同步。
与中定义的同步§17.4.5.:
如果一个动作x与后面的动作y同步,那么我们还有hb(x,y)。
(hb(x,y)=x发生在y之前)
因此,这保证了在读取和打印元素之前添加元素。
但是,在当前代码中,如果在启动另一个线程之后从主线程添加元素,那么将没有线程安全保证,并且行为未定义。另一个线程可能会看到添加的元素,但也可能看不到它们,甚至可能会抛出异常,因为它看到了
ArrayList
处于不一致的状态。如果我在a.start()之后添加另一个元素(比如a.addstring(“4”),那么我应该怎么做才能让新线程打印所有4个元素呢?
这很难用示例代码来回答,因为不清楚代码应该如何运行:
另一个线程(classb)是否应该无限期地等待新元素?然后一种解决方案可以是使用blockingqueue,或者使用某种信令,并且需要使用线程安全的集合(或者同步对arraylist的访问)。
如果另一个线程(classb)在添加新元素之前已经完成了旧元素的打印,是否允许它错过新元素?然后只需要使用线程安全的集合(或同步访问arraylist)。
...