Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/390.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_Arraylist - Fatal编程技术网

Java多线程-从列表中删除项

Java多线程-从列表中删除项,java,multithreading,arraylist,Java,Multithreading,Arraylist,这里是多线程新手,请耐心听我说。 我尝试运行两个线程,从任务列表中删除项目(总共10个任务),直到任务列表为空 到目前为止,我得到的是: 主要方法: public static void main(String[] args) { List<Task> taskList = new ArrayList<Task>(); List<Thread> threadList = new ArrayList<Thread>

这里是多线程新手,请耐心听我说。 我尝试运行两个线程,从任务列表中删除项目(总共10个任务),直到任务列表为空

到目前为止,我得到的是:

主要方法:

public static void main(String[] args) {


        List<Task> taskList = new ArrayList<Task>();
        List<Thread> threadList = new ArrayList<Thread>();


        for (int i = 1; i <= 10; i++) {

            taskList.add(new Task("some details");
        }

        TaskManager manager = new TaskManager();
        gestor.setTaskList(taskList);

        Thread t1 = new Thread(taskManager);            
        Thread t2 = new Thread(taskManager);    

        threadList.add(t1);
        threadList.add(t2);

        if(threadList.size() > 0){
            for (Thread thread : threadList){                               
                thread.start();             
            }
        }   

        for (Thread thread : threadList){
            try {
                thread.join();
            } catch (InterruptedException e) {
                System.out.println("thread " + Thread.currentThread().getName() + " was interrupted");
            }
        }

        System.out.println("END OF MAIN");

    }
总是同一个线程运行10次

我猜是因为您的列表太小,所以第一个线程运行并在第二个线程有机会开始工作之前完成任务。让任务列表更长,比如1000多个任务,甚至更多

它要么运行2次

这可能是因为任务列表不是线程安全的,请使用Collections.SynchronizedList使其成为线程安全的

    for (int i = 1; i <= 10; i++) {

        taskList.add(new Task("some details");
    }

    taskList = Collections.synchronizedList(taskList);

    TaskManager manager = new TaskManager();
for(int i=1;i
总是同一个线程运行10次

我猜是因为您的列表太小,所以第一个线程运行并在第二个线程有机会开始工作之前完成任务。将任务列表变长,比如1000多个任务,甚至更多

它要么运行2次

这可能是因为任务列表不是线程安全的,请使用Collections.SynchronizedList使其成为线程安全的

    for (int i = 1; i <= 10; i++) {

        taskList.add(new Task("some details");
    }

    taskList = Collections.synchronizedList(taskList);

    TaskManager manager = new TaskManager();

for(int i=1;i由于多个线程试图同时访问同一对象,您的代码存在一些并发问题。例如,可能发生的一件事是线程a从列表中获取任务(在
task task=availableTasks.get(index)
),然后有一个上下文切换,该任务被线程B删除,当线程a尝试删除该任务时,它已经消失了(这不会导致代码中出现异常,但它可能是坏的,具体取决于您计划对该任务执行什么操作)

当您尝试从列表中获取任务时,您也无法确定列表是否为空:当它上次在while循环中检查时,列表为空,但从那时起到它尝试执行任务时,另一个线程可能已经执行了最后一个任务。即使您删除对thread.sleep的调用,这也是正确的


您需要确保availableTasks列表一次只被一个线程修改。这可以通过多种方式完成,例如通过使用信号量,或者通过在共享数据对象中使用同步方法。由于多个线程同时尝试访问同一对象,您的代码会出现一些并发问题同一时间。例如,可能发生的一件事是线程A从列表中获取一个任务(在
task task=availableTasks.get(index)
),然后有一个上下文切换,该任务被线程B删除,当线程A尝试删除该任务时,它已经消失了(这不会在您的代码中导致异常,但它可能是不好的,这取决于您对任务的具体计划)

当您尝试从列表中获取任务时,您也无法确定列表是否为空:当它上次在while循环中检查时,列表为空,但从那时起到它尝试执行任务时,另一个线程可能已经执行了最后一个任务。即使您删除对thread.sleep的调用,这也是正确的

您需要的是确保availableTasks列表一次只被一个线程修改。这可以通过多种方式完成,例如使用信号量,或使用共享数据对象中的同步方法。

无法复制此操作

我已经纠正了(相当多)您代码的编译问题,并运行了它,得到:

Thread-1 printing some details for task 5
Thread-0 printing some details for task 8
Thread-0 printing some details for task 2
Thread-1 printing some details for task 7
Thread-1 printing some details for task 1
Thread-0 printing some details for task 3
Thread-0 printing some details for task 6
Thread-1 printing some details for task 9
Thread-0 printing some details for task 4
Thread-1 printing some details for task 0
因此,两个线程都运行和处理任务

重要的一点是,对任务列表的访问应该是同步的。不仅仅是
集合。synchronizedList
,您至少有四个位置可以访问任务列表。这就是为什么程序的执行几乎总是以以下方式结束:

java.lang.IllegalArgumentException: n must be positive
    at java.util.Random.nextInt(Random.java:250)
    at TaskManager.takeTask(TaskManager.java:25)
    at TaskManager.run(TaskManager.java:18)
    at java.lang.Thread.run(Thread.java:662)
您的
TaskManager.run
方法首先检查
isEmpty
,然后从列表中获取一个随机任务。另一个线程可能会在这两个操作之间删除列表中的最后一个任务。结果是
random.nextInt(0)
,尽管您之前已检查列表是否为空

最好是这样:

private Task nextTask() {
    synchronize(availableTask) {
        if (availableTask.isEmpty()) {
            return null;
        } else {
            return availableTasks.get(random.nextInt(availableTasks.size()));
        }
    }
}
不能复制这个

我已经纠正了(相当多)您代码的编译问题,并运行了它,得到:

Thread-1 printing some details for task 5
Thread-0 printing some details for task 8
Thread-0 printing some details for task 2
Thread-1 printing some details for task 7
Thread-1 printing some details for task 1
Thread-0 printing some details for task 3
Thread-0 printing some details for task 6
Thread-1 printing some details for task 9
Thread-0 printing some details for task 4
Thread-1 printing some details for task 0
因此,两个线程都运行和处理任务

重要的一点是,对任务列表的访问应该是同步的。不仅仅是
集合。synchronizedList
,您至少有四个位置可以访问任务列表。这就是为什么程序的执行几乎总是以以下方式结束:

java.lang.IllegalArgumentException: n must be positive
    at java.util.Random.nextInt(Random.java:250)
    at TaskManager.takeTask(TaskManager.java:25)
    at TaskManager.run(TaskManager.java:18)
    at java.lang.Thread.run(Thread.java:662)
您的
TaskManager.run
方法首先检查
isEmpty
,然后从列表中获取一个随机任务。另一个线程可能会在这两个操作之间删除列表中的最后一个任务。结果是
random.nextInt(0)
,尽管您之前已检查列表是否为空

最好是这样:

private Task nextTask() {
    synchronize(availableTask) {
        if (availableTask.isEmpty()) {
            return null;
        } else {
            return availableTasks.get(random.nextInt(availableTasks.size()));
        }
    }
}

添加到@Lidae回答的内容。这是标准的多生产者对多消费者问题。同一个问题上有几篇文章。

添加到@Lidae回答的内容。这是标准的多生产者对多消费者问题。同一个问题上有几篇文章。

您在哪里创建和启动多个线程?编辑with main Method您在哪里创建和启动多个线程?使用main methodCollections.synchronizedList编辑不够好。没有任何东西可以阻止两个线程执行同一任务。我注意到他的线程在每个任务之前都会休眠1秒,因此我的第一条语句可能也不正确。Collections.synchronizedList为n太好了。没有什么可以阻止两个线程执行同一个任务。我注意到他的线程在每个任务之前都会休眠1秒,所以我的第一句话可能也不正确。谢谢@Lidae,我使用了一个同步方法,问题得到了解决。我想他还需要一个可以选择索引和