Java 是否需要同步读取列表而不修改列表的方法?
我对合音还不熟悉。我知道,当我尝试使用多线程时,我可能会在向列表中添加内容时遇到问题。例如,使用以下代码:Java 是否需要同步读取列表而不修改列表的方法?,java,multithreading,Java,Multithreading,我对合音还不熟悉。我知道,当我尝试使用多线程时,我可能会在向列表中添加内容时遇到问题。例如,使用以下代码: import java.util.ArrayList; class MySafeList extends ArrayList<Double>{ static ArrayList<Double> mySafeList; public boolean add(Double d){ mySafeList.add(d);
import java.util.ArrayList;
class MySafeList extends ArrayList<Double>{
static ArrayList<Double> mySafeList;
public boolean add(Double d){
mySafeList.add(d);
return true;
}
public int size(){
return mySafeList.size();
}
public Double get(int i){
return mySafeList.get(i);
}
static boolean stressTest(int n, int m){
Thread threads[] = new Thread[n];
try{
for(int i=0; i<n; i++){
threads[i] = new Thread(new ThreadTest(1));
threads[i].start();
for(int j=0; j<m;j++){
Double d = new Double((double) j);
mySafeList.add(d);
}
}
return true;
}catch(Exception e){
return false;
}
}
public static void main(String[] args) {
MySafeList safeList = new MySafeList();
stressTest(2,4);
}
}
import java.util.ArrayList;
类MySafeList扩展了ArrayList{
静态数组列表mySafeList;
公共布尔加法(双d){
mySafeList.add(d);
返回true;
}
公共整数大小(){
返回mySafeList.size();
}
公共双获取(int i){
返回我的安全列表。获取(i);
}
静态布尔测试(int n,int m){
螺纹[]=新螺纹[n];
试一试{
对于(int i=0;i如果有代码可以在其他线程读取列表时修改列表,那么是的,您需要同步-以便在读取列表时不会修改列表
最简单的方法是将“synchronized”添加到“add”、“get”和“size”方法中
有人可能会质疑是否需要在“大小”上使用它,但我认为在这种情况下省略同步可能不会有什么好处,至少正如您在这里所写的那样
一个不相关的问题:为什么您的“add”调用返回一个硬连线的“true”值(使返回无效),而不是列表“add”中的值?如果您不需要知道某个项是否已实际添加,请将其设为void方法。如果要同步列表,请使用:
这是一个比我更好的答案,除非你的目的是通过自己编码来理解基本机制。因此,在将同步原语添加到add()
方法后,不必在不修改列表的情况下同步读取列表的方法(size()
和get()
)?如果您使用的是synchronizedList,则不需要同步任何add、size、get,因为synchronizedList是为您而做的。事实上,似乎不需要您的整个类MySafeList:只需使用synchronizedList即可。但这是否需要取决于您编写此代码的目的。这是不正确的。您需要同步,句号。“在其他线程读取时修改列表”不是全部。问题是可见性。写入(或其他操作)除非读和写都是同步的,否则不能保证在Java的内存模型中是可见的,而且它们必须在同一个锁/监视器上同步。请参考关于这个主题的其他文章,并在实践中获得Brian Goetz的Java并发性的副本,这确实是关于Java多线程的最好的书。我想这在一开始是正确的方法。但是在阅读@markspace comment之后,我感到困惑。其次,我的'add'调用返回一个硬连接的'true',只要我有错误,如果我没有。我将再次检查。哦,对了。您的代码扩展了ArrayList,所以您希望保留'add'的语义和签名。但是硬连接是真的不正确;您应该返回基础“add”调用的结果。类结构似乎很奇怪。您的类扩展了ArrayList,但存在一个静态ArrayList。这意味着在执行MySafeList x=new MySafeList()之后
ArrayList有两个实例,其中一个大部分未使用,除了所有未重写的方法。这会让人感到困惑,例如size()可能返回非零,但isEmpty()将说是真的,因为您没有覆盖它..然后,如果您也执行MySafeList y=new MySafeList();//第二个列表
,有时x和y是相同的列表(添加到x的内容显示在y中,反之亦然),有时则不是(任何您没有覆盖的ArrayList方法)。
List<Double> mySafeList = Collections.synchronizedList(new ArrayList<>());
List<Double> mySafeList = new CopyOnWriteArrayList<>();