简体   繁体   English

使用3个线程将元素添加到5个ArrayList中:arraylist大小的总和总是不同的

[英]Adding elements into 5 ArrayList with 3 threads: the sum of the arraylist's size is always different

The Company class contains 5 ArrayList, that I'm trying to update with 3 threads. Company类包含5个ArrayList,我正尝试使用3个线程进行更新。 The addToWorkers() method gets the type of the Employee subclasses, and adds them to the corresponding array. addToWorkers()方法获取Employee子类的类型,并将它们添加到相应的数组中。 I'm using the LazyHolder class because my Company singleton instance has to be static, and it should provide synchronization. 我使用LazyHolder类是因为我的Company单例实例必须是静态的,并且它应该提供同步。

public class Company {

    private static class LazyHolder {
        private static final Company INSTANCE = new Company();
}

    private volatile List<ProjectLeader> projectLeaders = new ArrayList<>();
    private volatile List<ConsultantLeader> consultantLeaders = new ArrayList<>();
    private volatile List<DeveloperLeader> developerLeaders = new ArrayList<>();
    private volatile List<DeveloperWorker> developerWorkers = new ArrayList<>();
    private volatile List<ConsultantWorker> consultantWorkers = new ArrayList<>();

    private Company() {
    }

    public static Company getInstance() {
        return LazyHolder.INSTANCE;
    }

    public synchronized <T extends Employee> void addToWorkers(T t) {
        Position p = t.getPosition();
        switch (p) {
            case DEVELOPER_WORKER: Company.getInstance().developerWorkers.add((DeveloperWorker) t);
                break;
            case DEVELOPER_LEADER: Company.getInstance().developerLeaders.add((DeveloperLeader) t);
                break;
            case CONSULTANT_WORKER: Company.getInstance().consultantWorkers.add((ConsultantWorker) t);
                break;
            case CONSULTANT_LEADER: Company.getInstance().consultantLeaders.add((ConsultantLeader) t);
                break;
            case PROJECT_LEADER: Company.getInstance().projectLeaders.add((ProjectLeader) t);
                break;
        }
    }
}

The Runner class implements the Runnable interface: Runner类实现Runnable接口:

public class Runner implements Runnable {

    private Random random = new Random();
    private Position[] positions = Position.values();

    final Position randomPosition(){
        return positions[random.nextInt(positions.length)];
    }

    public void run() {
        for (int i = 1; i <= 350; i++) {
            Position p = randomPosition();
            switch (p) {
                case PROJECT_LEADER:
                Company.getInstance().addToWorkers(new ProjectLeader(p, "projectLeader"));
                    break;
                case DEVELOPER_LEADER:
                Company.getInstance().addToWorkers(new DeveloperLeader(p, "developerLeader"));
                    break;
                case CONSULTANT_LEADER:
                    Company.getInstance().addToWorkers(new ConsultantLeader(p, "consultantLeader"));
                    break;
                case DEVELOPER_WORKER:
                Company.getInstance().addToWorkers(new DeveloperWorker(p, "developerWorker"));
                    break;
                case CONSULTANT_WORKER:
                Company.getInstance().addToWorkers(new ConsultantWorker(p, "consultantWorker"));
                    break;
            }
        }
    }
}

Since all the List type variables are volatile and the method I'm using is synchronized I'd expect, that if I run my main method, and get the sum of the size of each array, I'd get exactly 1050 each time, but I dont, it's always between 1000-1100, or sometimes ArrayIndexOutOfBoundsException : 由于所有List类型变量都是volatile并且我使用的方法是synchronized所以我希望,如果我运行main方法并获取每个数组的大小总和,则每次将得到1050,但我不知道,它总是在1000-1100之间,有时甚至是ArrayIndexOutOfBoundsException

    t1.start();
    t2.start();
    t3.start();
    try {
        t1.join();
        t2.join();
        t3.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    System.out.println(Company.getInstance().getConsultantLeaders().size() +
            Company.getInstance().getDeveloperWorkers().size() +
            Company.getInstance().getConsultantLeaders().size() +
            Company.getInstance().getDeveloperLeaders().size() +
            Company.getInstance().getProjectLeaders().size());

What am I missing here? 我在这里想念什么?

According to your logic there is no reason to make your lists visible for all threads, 根据您的逻辑,没有理由让您的列表在所有线程中可见,

public synchronized <T extends Employee> void addToWorkers(T t) 

is enough to make it thread safe, but with this way there is no point to use multithreading. 足以使其线程安全,但是使用这种方式就没有必要使用多线程了。

I suggest you to define your lists like this : 我建议您这样定义列表:

private  List<ProjectLeader> projectLeaders = Collections.synchronizedList(new ArrayList<>());
private  List<ConsultantLeader> consultantLeaders = Collections.synchronizedList(new ArrayList<>());
private  List<DeveloperLeader> developerLeaders = Collections.synchronizedList(new ArrayList<>());
private  List<DeveloperWorker> developerWorkers = Collections.synchronizedList(new ArrayList<>());
private  List<ConsultantWorker> consultantWorkers = Collections.synchronizedList(new ArrayList<>());

Now we can solve your real problem , this one is funny :) 现在我们可以解决您的实际问题,这个很有趣:)

Check your sum, you are not adding to consultantworkers to the sum, you are adding consultant leaders for twice : 检查您的总和,您没有将总和添加到顾问工作人员中,而是两次添加了顾问负责人:

 System.out.println(
        Company.getInstance().getConsultantLeaders().size() + // leaders
        Company.getInstance().getDeveloperWorkers().size() +
        Company.getInstance().getConsultantLeaders().size() +//this one must be workers 
        Company.getInstance().getDeveloperLeaders().size() +
        Company.getInstance().getProjectLeaders().size()); 

you need also workers ;) 您还需要工人;)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM