Java多线程-从列表中删除项
这里是多线程新手,请耐心听我说。 我尝试运行两个线程,从任务列表中删除项目(总共10个任务),直到任务列表为空 到目前为止,我得到的是: 主要方法: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>
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,我使用了一个同步方法,问题得到了解决。我想他还需要一个可以选择索引和