Java 同步对ArrayList的访问

Java 同步对ArrayList的访问,java,multithreading,concurrency,locking,concurrentmodification,Java,Multithreading,Concurrency,Locking,Concurrentmodification,我试图通过并行计算来计算任意数的所有素数。我知道isPrime()可以从现在的情况得到改进,但主要问题是我无法同步对存储结果的ArrayList的访问。我实例化了一个虚拟对象“m”,作为对数组的监视和控制访问。显然,我在推理过程中犯了一个错误,因为每次我都会得到一个java.util.ConcurrentModificationException。注意: 编辑:更新以显示建议后的完成情况 import java.util.ArrayList; 公共班机{ 静态最终整数最大值=100000000;

我试图通过并行计算来计算任意数的所有素数。我知道isPrime()可以从现在的情况得到改进,但主要问题是我无法同步对存储结果的ArrayList的访问。我实例化了一个虚拟对象“m”,作为对数组的监视和控制访问。显然,我在推理过程中犯了一个错误,因为每次我都会得到一个java.util.ConcurrentModificationException。注意:

编辑:更新以显示建议后的完成情况

import java.util.ArrayList;
公共班机{
静态最终整数最大值=100000000;
静态final int THREADS=Runtime.getRuntime().availableProcessors();
静态最终int ARRINITSIZE=100000;
静态ArrayList素数=新ArrayList(ARRINITSIZE);
公共静态void main(字符串[]args){
线程[]t=新线程[线程];
PrimeRun.m=新监视器();

对于(inti=0;i将素数声明为

static List<Integer> primes = Collections.synchronizedList(new ArrayList<Integer>(ARRINITSIZE));
static List primes=Collections.synchronizedList(新的ArrayList(ARRINITSIZE));
您应该能够摆脱监视器和同步块…哦,您必须等到计算素数的线程完成后,才能开始打印素数列表中的值

编辑

这里是修改后的程序,它只是等待线程完成

    import java.util.ArrayList;
    import java.util.List;

    public class Main {
        static final int MAX = 1000;
        static final int THREADS = Runtime.getRuntime().availableProcessors();
        static final int ARRINITSIZE = 100000;
        static ArrayList<Integer> primes = new ArrayList<Integer>(ARRINITSIZE);

    public static void main(String[] args) {
        PrimeRun.m = new Monitor();

        List<Thread> thread = new ArrayList<Thread>();
        for (int i=0; i<THREADS; i++){
            Thread t = new Thread(new PrimeRun(i));
            t.start();
           thread.add(t);
        }

        for (Thread t : thread) {
            if (t.isAlive()){
                try {
                    t.join();
                } catch (InterruptedException e) {

                }
            }

        }

        for (int n : primes)
            System.out.print("" + n + " ");
    }

    static boolean isPrime(int n) {
        if (n <= 1 || (n&1) == 0) return false;
        if (n == 2 || n == 3 || n == 5) return true;

        for (int i = 3; n*n <= i; i += 2)
            if (n % i == 0) return false;

        return true;
    }

    synchronized static void addPrime(int n) {
        primes.add(n);
    }

}

    class PrimeRun implements Runnable {
        public static Monitor m;
        final int ID;
        public PrimeRun(int i) {
            ID = i;
        }

        public void run() {
        for(int i=0; i < Main.MAX; i++) {
            if(i % Main.THREADS == ID)
                if(Main.isPrime(i)) 
                    m.addPrime(i);
            }
        }
    }

    class Monitor {
        public synchronized void addPrime(int n) {
            Main.addPrime(n);
        }
    }
import java.util.ArrayList;
导入java.util.List;
公共班机{
静态最终整数最大值=1000;
静态final int THREADS=Runtime.getRuntime().availableProcessors();
静态最终int ARRINITSIZE=100000;
静态ArrayList素数=新ArrayList(ARRINITSIZE);
公共静态void main(字符串[]args){
PrimeRun.m=新监视器();
列表线程=新的ArrayList();

对于(int i=0;i您会得到
ConcurrentModificationException
,因为您在向数组添加时正在对数组进行迭代。这与多个线程无关,甚至会在单个线程中发生。但在您的特定情况下,会发生这种情况,因为当您开始对列表进行迭代时,线程仍在添加素数。为了防止这种情况发生,您必须等待所有线程完成后再打印。为此,您可以迭代线程数组并对每个线程调用
join()
。或者您可以使用


列表可以通过集合进行同步。synchronizedList()
如另一个答案中所建议。

ConcurrentModificationException的原因是同步不错。原因是您正在对列表进行迭代期间对其进行修改

我在代码中发现的唯一迭代是

for (int n : primes)
      System.out.print("" + n + " ");
下面是发生的情况。 您正在运行多个执行其任务并向集合添加元素的线程。运行线程的代码后面紧跟着迭代列表并打印其元素的代码。因此,迭代和您的工作线程同时运行

要解决此问题,应等待所有工作线程完成后再打印。确实,您希望仅在所有计算完成后打印结果。请签出方法
Thread.join()
,以实现此功能


显然,要按照@maneesh的建议去做,即使用
Collections.synchronizedList()
而不是手动同步。

我想了解并发编程的详细信息。否则,我会选择这个。因此,主要来说,应该保留对派生线程的引用,然后加入()请查看编辑后的代码答案,等待线程完成。如果要在迭代列表时尝试添加列表,请先将其转换为数组并迭代数组。要对
isPrime()
方法进行注释,而不是除以i+=2,请尝试除以素数。get(i++)。这可以防止你在通过3和5之后被15除。@gobernador你的意思是,读取数组中已经计算过的素数,并用该数字进行模运算?还是说用不同的值增加循环计数器?用小于测试数字的素数进行模运算。这将减少计算并给出y在素数较少的情况下,在更高的数字上,速度有了很大的提高。@gobernador现在的情况是,素数[]没有排序,所以这不会起作用,除非我阻止一些线程,直到每个数字的第n个线程完成,这样它们就按顺序插入了,对吗?我认为顺序并不重要。是否使用素数[]应该可以很好地解决问题已排序或未排序。