arraylist上的java Volatile/synchronization
我的程序如下所示:arraylist上的java Volatile/synchronization,java,multithreading,thread-safety,synchronized,volatile,Java,Multithreading,Thread Safety,Synchronized,Volatile,我的程序如下所示: public class Main { private static ArrayList<T> list; public static void main(String[] args) { new DataListener().start(); new DataUpdater().start(); } static class DataListener extends Thread {
public class Main {
private static ArrayList<T> list;
public static void main(String[] args) {
new DataListener().start();
new DataUpdater().start();
}
static class DataListener extends Thread {
@Override
public void run() {
while(true){
//Reading the ArrayList and displaying the updated data
Thread.sleep(5000);
}
}
}
static class DataUpdater extends Thread{
@Override
public void run() {
//Continuously receive data and update ArrayList;
}
}
}
公共类主{
私有静态数组列表;
公共静态void main(字符串[]args){
新建DataListener().start();
新建DataUpdater().start();
}
静态类DataListener扩展线程{
@凌驾
公开募捐{
while(true){
//读取ArrayList并显示更新的数据
睡眠(5000);
}
}
}
静态类DataUpdater扩展线程{
@凌驾
公开募捐{
//持续接收数据并更新ArrayList;
}
}
}
为了在两个线程中使用此ArrayList,我知道两个选项:
我是否误解了这里的任何概念,或者是否有另一种选择使之成为可能?事实上,这两种解决方案都不够。实际上,您需要同步arraylist上的完整迭代,以及对arraylist的每次写入访问:
synchronized(list) {
for (T t : list) {
...
}
}
及
这根本帮不了你。
volatile
的意思是线程A对共享变量所做的更改对线程B立即可见。通常,这样的更改可能在某些缓存中,仅对创建它们的线程可见,volatile
只是告诉JVM不要进行任何缓存或优化,否则会导致值更新延迟
因此,这不是一种同步手段。这只是确保变化可见度的一种手段。此外,它是对变量的更改,而不是对该变量引用的对象的更改。也就是说,如果将列表
标记为volatile
,则只有将新列表分配给列表
,而不是更改列表的内容,才会产生任何影响
您的另一个建议是将
ArrayList
设置为同步变量。这里有一个误解。无法同步变量。唯一可以同步的是代码——要么是整个方法,要么是其中的特定块。将对象用作同步监视器
监视器是对象本身(实际上,它是对象的逻辑部分,即监视器),而不是变量。如果在对旧值进行同步后将不同的对象分配给同一变量,则旧监视器将不可用
但无论如何,同步的不是对象,而是您决定使用该对象同步的代码
因此,您可以使用列表
作为监视器来同步其上的操作。但是您不能使列表
同步
假设您想使用列表作为监视器来同步操作,您应该设计它,使writer线程不会一直持有锁。也就是说,它只需抓取它进行一次读取更新、插入等操作,然后将其释放。再次抓取它进行下一次操作,然后释放它。如果同步整个方法或整个更新循环,则另一个线程将永远无法读取它 在阅读线程中,您可能应该执行以下操作:
List<T> listCopy;
synchronized (list) {
listCopy = new ArrayList(list);
}
// Use listCopy for displaying the value rather than list
列表复制;
已同步(列表){
listCopy=新的ArrayList(列表);
}
//使用listCopy显示值而不是列表
这是因为显示可能很慢-可能涉及I/O、更新GUI等。因此,为了最小化锁定时间,您只需从列表中复制值,然后释放监视器,以便更新线程可以完成其工作
除此之外,
java.util.concurrent
包等中有许多类型的对象,用于在这样的情况下提供帮助,其中一方在写,另一方在读。查看文档-也许一个ConcurrentLinkedQue
对您有用
不能使ArrayList
易失性
。您不能使任何对象不稳定。Java中唯一可以不稳定的是字段
在您的示例中,list
不是ArrayList
private static ArrayList<T> list;
执行该行后,列表已更改,但字段仍引用相同的列表对象。这是另一种可能性,但不会有太大更改,因为OP只有一个读卡器。同意,如果OP选择ConcurrentSkipList怎么办?JDK中没有此类类。无论如何,如果不知道确切的用例,我无法提供最佳解决方案。我所知道的是,两个线程必须同时访问一个列表。您可以使用
并发
包中的一个队列,而不是ArrayList
。您不能使ArrayList变为volatile
。您不能使任何对象不稳定。Java中唯一不稳定的东西是字段。但是,为什么在这种情况下我需要同步?@Xander,因为列表上的操作不是原子的。在另一个线程的更新中间进行的读取可以看到它处于不一致的状态。例如,如果删除ArrayList中的一个项,则所有其他项都会复制到左侧的一个位置。如果您的读者当时正在阅读,它可能会因此跳过某个项目。这很有意义!非常感谢。如果我复印一份
private static ArrayList<T> list;
list.add(e);