能否创建10个线程存入ArrayList并实现线程复用?
1. 能否创建10个线程存入ArrayList?
完全可以。ArrayList是Java中常用的动态数组容器,支持存储任意类型的对象,Thread(或自定义线程子类)作为对象自然可以存入其中。
不过你提供的示例代码存在问题:
threads = new ArrayList<>(10); for (int i = 0; i < numThreads; i++) { WorkerThread thread = new WorkerThread(threads); threads.add(thread); threads.add(thread); // 这里重复添加了同一个线程对象 thread.start(); }
这段代码里,每次循环会把同一个WorkerThread对象添加两次到集合中,实际存储的是同一个线程的引用,并不是创建了2倍数量的线程。如果要创建10个独立线程,应该确保循环内每次创建新的线程实例,且只添加一次:
int numThreads = 10; List<WorkerThread> threads = new ArrayList<>(numThreads); for (int i = 0; i < numThreads; i++) { WorkerThread thread = new WorkerThread(); threads.add(thread); thread.start(); }
2. 能否从ArrayList取出线程执行任务后再放回?
这里要注意线程的生命周期限制:Java中一个Thread对象调用start()后,线程进入执行状态,一旦任务完成线程终止,就无法再次调用start()重启。所以如果你的WorkerThread是执行完任务就结束的普通线程,即使从集合中取出,也无法再次执行任务。
如果要实现线程的复用(取出后执行新任务),需要自定义支持任务复用的工作线程,让线程执行完一个任务后不终止,而是等待下一个任务。示例实现如下:
自定义可复用WorkerThread
class WorkerThread extends Thread { private BlockingQueue<Runnable> taskQueue; private volatile boolean isRunning = true; public WorkerThread(BlockingQueue<Runnable> taskQueue) { this.taskQueue = taskQueue; } @Override public void run() { while (isRunning) { try { // 等待并取出任务执行 Runnable task = taskQueue.take(); task.run(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; } } } // 停止线程 public void stopThread() { isRunning = false; this.interrupt(); } }
结合ArrayList管理线程并分配任务
public class ThreadPoolDemo { public static void main(String[] args) throws InterruptedException { int numThreads = 10; BlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<>(); List<WorkerThread> threads = new ArrayList<>(numThreads); // 创建10个线程并启动,存入ArrayList for (int i = 0; i < numThreads; i++) { WorkerThread thread = new WorkerThread(taskQueue); threads.add(thread); thread.start(); } // 提交任务:无需从ArrayList显式取出线程,直接往任务队列加任务即可 taskQueue.add(() -> System.out.println("任务1执行,线程:" + Thread.currentThread().getName())); taskQueue.add(() -> System.out.println("任务2执行,线程:" + Thread.currentThread().getName())); // 模拟任务执行时间 Thread.sleep(2000); // 再次提交新任务,线程会自动取出执行 taskQueue.add(() -> System.out.println("新任务执行,线程:" + Thread.currentThread().getName())); // 关闭线程 for (WorkerThread thread : threads) { thread.stopThread(); } } }
这种方式下,线程会一直循环等待任务,你不需要手动从ArrayList取出线程执行任务,只需要往任务队列添加任务即可,线程会自动处理。如果确实需要从ArrayList中取出指定线程分配任务,可以扩展WorkerThread,给每个线程单独设置任务队列,但这种方式不如统一任务队列高效。
3. 线程完成任务后,能否移除再重新添加以执行新任务?
如果是普通的Thread(执行完任务就终止),即使从ArrayList中移除再添加,也无法再次调用start()启动,因为线程已经处于终止状态,再次调用会抛出IllegalThreadStateException。
如果是上述自定义的可复用WorkerThread,移除再添加是可以的,但完全没必要——因为这类线程本身就处于存活状态,等待新任务,直接给它分配新任务即可,不需要移除再添加。
另外,更推荐使用Java标准库提供的ExecutorService线程池来管理线程,它已经封装了线程的创建、复用、销毁逻辑,比手动用ArrayList管理更安全高效:
ExecutorService executor = Executors.newFixedThreadPool(10); // 提交任务 executor.submit(() -> System.out.println("任务执行")); // 提交新任务 executor.submit(() -> System.out.println("新任务执行")); // 关闭线程池 executor.shutdown();
内容的提问来源于stack exchange,提问作者Polash

