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

时间:2017-03-16 11:28:45

标签: java multithreading

Company类包含5个ArrayList,我正在尝试用3个线程更新。 addToWorkers()方法获取Employee子类的类型,并将它们添加到相应的数组中。我正在使用LazyHolder类,因为我的公司单例实例必须是静态的,它应该提供同步。

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;
        }
    }
}

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;
            }
        }
    }
}

由于所有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());

我在这里缺少什么?

1 个答案:

答案 0 :(得分:0)

根据您的逻辑,没有理由让您的列表对所有线程都可见

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

足以使其线程安全,但通过这种方式使用多线程是没有意义的。

我建议您定义这样的列表:

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<>());

现在我们可以解决你的真正问题,这个很有趣:)

检查您的金额,您不是要向顾问工作者添加金额,您要两次添加顾问领导者:

 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()); 

你还需要工人;)