Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/328.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 通过两个线程同步ArrayList_Java_Multithreading_Arraylist - Fatal编程技术网

Java 通过两个线程同步ArrayList

Java 通过两个线程同步ArrayList,java,multithreading,arraylist,Java,Multithreading,Arraylist,我很难理解如何在两个线程上同步ArrayList。基本上,我希望一个线程将对象附加到列表中,另一个线程同时读取该列表中的对象 下面是部署线程的类: public class Main { public static ArrayList<Good> goodList = new ArrayList(); public static void main(String[] args) { Thread thread1 = new Thread(new Goo

我很难理解如何在两个线程上同步ArrayList。基本上,我希望一个线程将对象附加到列表中,另一个线程同时读取该列表中的对象

下面是部署线程的类:

public class Main {
    public static ArrayList<Good> goodList = new ArrayList();
    public static void main(String[] args) {
        Thread thread1 = new Thread(new GoodCreator());
        Thread thread2 = new Thread(new WeightCounter());
        thread1.start();
        thread2.start();
    }
}

非常感谢您提供的任何帮助

您正在运行两个独立运行的线程。这些线程可以以任何顺序运行,如果一个线程停止(例如读取文件),另一个线程不认为它必须等待它

简而言之,第二个线程在第一个线程向列表中添加任何内容之前完成

没有很好的修复方法,因为这不是一个很好的例子,说明了为什么要使用多个线程,但是为了得到结果,您可以做的就是这样

public class WeightCounter implements Runnable{
    private ArrayList<Good> goodList = Main.goodList;
    @Override
    public void run() {
        System.out.println("Thread 2 started");
        for(int i = 0; i < 10; i++) {
           try {
               Thread.sleep(100);
           } catch (InterruptedException ie) {
               throw AssertionError(ie);
           }
           int weightSum = 0;
           synchronized(goodList){
               for (Good g : goodList)
                    weightSum += g.getWeight();
           }
           System.out.println(weightSum);
        }
    }
}
公共类WeightCounter实现可运行{
private ArrayList goodList=Main.goodList;
@凌驾
公开募捐{
System.out.println(“线程2已启动”);
对于(int i=0;i<10;i++){
试一试{
睡眠(100);
}捕获(中断异常ie){
抛出断言错误;
}
int-weightSum=0;
已同步(goodList){
for(Good g:goodList)
weightSum+=g.getWeight();
}
系统输出打印项次(加权和);
}
}
}

这将打印总和10次,间隔0.1秒。根据加载文件所需的时间,您将能够看到迄今为止加载的内容的总和。

WeightCounter
类中尝试此更改

public class WeightCounter implements Runnable{
   private ArrayList<Good> goodList = Main.goodList;
   @Override
   public void run() {
      System.out.println("Thread 2 started");
      int weightSum = 0;
      while(goodList.isEmpty()) {
        Thread.sleep(1000);
      }
      synchronized(goodList){
        for(Good g : goodList){
            weightSum += g.getWeight();
        }
     }
     System.out.println(weightSum);
   }
}
公共类WeightCounter实现可运行{
private ArrayList goodList=Main.goodList;
@凌驾
公开募捐{
System.out.println(“线程2已启动”);
int-weightSum=0;
while(goodList.isEmpty()){
睡眠(1000);
}
已同步(goodList){
for(Good g:goodList){
weightSum+=g.getWeight();
}
}
系统输出打印项次(加权和);
}
}

此更改将导致
WeightCounter
线程等待另一个线程完成向
goodList
填充数据,然后再尝试从中读取数据。

这就是所谓的生产者-消费者任务。你可以用arraylist来做,但老实说,这不是解决这个问题的正确方法

幸运的是,Java为我们提供了一些集合,BlockingQueue集合,它们是专门为此而设计的

//the collection with the stuff in it
static BlockingQueue<Object> items = new BlockingQueue<Object>();
//(there are a few different types of blocking queues, check javadocs.
//you would want Linked or Array blocking queue

//what happens on the reader thread
public void producer()
{
    //read the data into the collection
    for (all the data in the file)
    {
       //add the next item
       items.put(/* next item from file or w/e */);

       //stop if necessary
       if (atEndOfFile) stillReadingData = false;

       //etc
    }
}
通过这种方式,您可以使用producer线程不断地将项目添加到队列中,并且一旦消费者线程空闲,这些项目就会被处理(这种方法可以很好地扩展到许多消费者线程)。如果您仍然需要项目的集合,则应创建第二个集合,并在处理完项目后将其添加到该集合中


作为补充说明,您可能仍然需要同步处理项目时发生的操作。例如,您需要同步“weightSum”上的增量(或者交替使用AtomicInteger)。

您可以使用
ArrayBlockingQueue
。链接:您必须使用ArrayList吗?并发库中的队列如何?这不是一个可复制的示例…@YassinHajaj这就是为什么很难找到并发bug的原因:它们通常是不可复制的。在这种情况下,两个线程之间存在明显的数据竞争。您的示例有两个问题:1)它没有等待另一个线程完成填充
goodList
:它等待另一个线程开始填充它。2) 它不同步地访问
goodList.isEmpty()
。当线程A更新某个变量(例如,列表的长度)时,无法保证线程B何时(甚至是否)能够看到更改,除非两个线程都在使用某种同步。1。同意。该示例仅为提问者提供一些进展,并不代表应该如何编写正确的多线程代码。2.在while循环中对
goodList
进行同步将导致另一个问题:死锁,这就是我忽略它的原因,并尝试阻止可能引发的
InterruptedException
。您不需要(或想要!)在睡眠时对锁进行同步,但是,如果轮询长度的线程在从内存获取值时没有在锁上同步,那么Java语言规范就不要求线程看到长度>0,不管其他线程向列表中添加了多少项。当然,在大多数JVM中,轮询线程将看到长度>0,但关键是,除非该程序对于规范允许的每个JVM行为都是正确的,否则不能调用正确的程序。
public class WeightCounter implements Runnable{
    private ArrayList<Good> goodList = Main.goodList;
    @Override
    public void run() {
        System.out.println("Thread 2 started");
        for(int i = 0; i < 10; i++) {
           try {
               Thread.sleep(100);
           } catch (InterruptedException ie) {
               throw AssertionError(ie);
           }
           int weightSum = 0;
           synchronized(goodList){
               for (Good g : goodList)
                    weightSum += g.getWeight();
           }
           System.out.println(weightSum);
        }
    }
}
public class WeightCounter implements Runnable{
   private ArrayList<Good> goodList = Main.goodList;
   @Override
   public void run() {
      System.out.println("Thread 2 started");
      int weightSum = 0;
      while(goodList.isEmpty()) {
        Thread.sleep(1000);
      }
      synchronized(goodList){
        for(Good g : goodList){
            weightSum += g.getWeight();
        }
     }
     System.out.println(weightSum);
   }
}
//the collection with the stuff in it
static BlockingQueue<Object> items = new BlockingQueue<Object>();
//(there are a few different types of blocking queues, check javadocs.
//you would want Linked or Array blocking queue

//what happens on the reader thread
public void producer()
{
    //read the data into the collection
    for (all the data in the file)
    {
       //add the next item
       items.put(/* next item from file or w/e */);

       //stop if necessary
       if (atEndOfFile) stillReadingData = false;

       //etc
    }
}
//what happens on the other threads
public void consumer()
{


   //keep this thread alive so long as there is data to process
   //or so long as there might be more data to process
   while (stillReadingData || !items.isEmpty())
   {
       //get the next item from the list
       //while the list is empty, we basically sleep for "timeout" timeunits,
       //then the while-loop would repeat, and so on
       Object o = items.poll(long timeout, int units);
       if (o != null) //process it
   }
}