Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 后台线程复制集合并重新初始化原始集合,可能吗?_Java_Multithreading_Concurrency - Fatal编程技术网

Java 后台线程复制集合并重新初始化原始集合,可能吗?

Java 后台线程复制集合并重新初始化原始集合,可能吗?,java,multithreading,concurrency,Java,Multithreading,Concurrency,假设我有一门课: public class Chat { private volatile ConcurrentLinkedQueue messages = new ConcurrentLinkedQueue(); // getter/setter for messages queue } 我有一个后台线程,它将这个类的一个实例作为参数: Thread t = new Thread(new QueuePersister(messages)); t.start(); 其中线程的任务是

假设我有一门课:

public class Chat {
  private volatile ConcurrentLinkedQueue messages = new ConcurrentLinkedQueue();

  // getter/setter for messages queue
}
我有一个后台线程,它将这个类的一个实例作为参数:

Thread t = new Thread(new QueuePersister(messages));
t.start();
其中线程的任务是:

public class QueuePersister implements Runnable {
   private volatile ConcurrentLinkedQueue messages = new ConcurrentLinkedQueue(); 

   public QueuePersister(ConcurrentLinkedQueue messages) {
     this.messages = messages;
   }

   @Override
    public void run() {
        while(true) {

            // this is a 2 step process, probably should synchronize?? i.e. copy and re-initializing
            ConcurrentLinkedQueue copy = messages;
            messages = new ConcurrentLinkedQueue();

            // save to disk using the copy queue


            // sleep for x seconds
         }
    }
}
我想做的是:

我的消息被保存到队列中,后台线程每x秒制作一个队列副本,重新设置原始消息队列,以便在旧副本被持久化到文件/db的同时开始获取新数据

这样,将来的任何写入操作都将执行到新队列

在我的测试中,这不起作用,因为我似乎无法重新初始化传递到线程中的队列

我认为这是因为消息队列是通过引用传入的,但它正在传递引用的副本,不允许您更改引用。您可以更改所引用的对象,但不能更改引用。

如果这是真的,那么我必须做什么呢?我可以在课堂聊天中公开一些方法吗

注意:当我的应用程序运行时,聊天对象只创建一次

聊天对象将由多个线程访问

更新


只有一个线程会执行此“持久性”,我希望它在Chat.messages队列上工作。我想让它做的只是复制一个集合,然后重新设置聊天室的集合,然后它就可以花时间将复制的队列版本保存到磁盘上。

所以线程中的
消息与
聊天
类中的
消息不同,对吗?所以当你这样做的时候:

   ConcurrentLinkedQueue copy = messages;
   messages = new ConcurrentLinkedQueue();
这只会影响
线程
收集字段。您不需要它是易变的,也不需要它是并发的

我怀疑您正在尝试使用线程中的集合。由于您使用的是
ConcurrentLinkedQueue
,因此可以从另一个线程对队列执行操作,而无需执行复制和替换操作。当其他线程添加到队列中时,您可以安全地从队列中删除项目。这就是并发类的全部目的


您应该将
Chat
中的
messages
字段标记为
private final
,而不是volatile,因为它不需要更改。您还可以在
线程内将其标记为final

以便线程内的
消息
聊天
类中是不同的
消息
,对吗?所以当你这样做的时候:

   ConcurrentLinkedQueue copy = messages;
   messages = new ConcurrentLinkedQueue();
这只会影响
线程
收集字段。您不需要它是易变的,也不需要它是并发的

我怀疑您正在尝试使用线程中的集合。由于您使用的是
ConcurrentLinkedQueue
,因此可以从另一个线程对队列执行操作,而无需执行复制和替换操作。当其他线程添加到队列中时,您可以安全地从队列中删除项目。这就是并发类的全部目的

您应该将
Chat
中的
messages
字段标记为
private final
,而不是volatile,因为它不需要更改。你也可以把它标记在<代码>线程< /代码>中。

< p>我会考虑使用A代替。它有一个
drainTo
方法,将队列中的内容清空到另一个队列中。此时,您可以将LinkedBlockingQueue声明为final

Javadoc

public int drainTo(集合c)

从此队列中删除所有可用元素并将其添加到 给定集合。此操作可能比重复操作更有效 正在轮询此队列。尝试添加时遇到错误 集合c中的元素可能导致元素不在其中, 引发关联异常时,集合中的一个或两个集合。 尝试将队列排入自身会导致 非法辩论例外。此外,此操作的行为是 如果在执行操作时修改了指定的集合,则未定义 正在进行中

我会考虑用A代替。它有一个
drainTo
方法,将队列中的内容清空到另一个队列中。此时,您可以将LinkedBlockingQueue声明为final

Javadoc

public int drainTo(集合c)

从此队列中删除所有可用元素并将其添加到 给定集合。此操作可能比重复操作更有效 正在轮询此队列。尝试添加时遇到错误 集合c中的元素可能导致元素不在其中, 引发关联异常时,集合中的一个或两个集合。 尝试将队列排入自身会导致 非法辩论例外。此外,此操作的行为是 如果在执行操作时修改了指定的集合,则未定义 正在进行中


只有一个线程将执行此操作,我希望它作用于聊天室的队列U。在线程中处理聊天室集合的问题是,循环存在问题,因为在循环时,项目将添加到队列中。我只是想知道我是否可以按我想要的方式来做(因为我可能会将concurrentlinkqueue与一个在其上同步的常规linkedlist交换)。这取决于并发操作@Blankman。如果其他线程只是添加到队列中,那么您可以遍历队列并处理线程中的条目,而不会出现问题。只有当两个线程正在处理队列中的项目——对对象进行更改时,才会出现问题。如果只有一个消费者,那么你就不需要跳复制/替换舞。我明白了,但理论上,我怎么能跳复制/替换舞呢?你能给我一根线吗