一、介绍
在Java并发编程中,线程池是一种重要的技术。通过线程池执行任务可以大大减少资源的开销,提高程序的性能,避免线程过多导致系统资源耗尽的情况。而Executors类就是Java提供的一个专门用于创建和管理线程池的工具类。
二、使用步骤
- 创建线程池
创建线程池的方式有多种,其中Executors类提供了丰富的静态方法来创建不同类型的线程池。比较常用的是newFixedThreadPool()方法,可以创建指定数量的线程,如下所示:
ExecutorService executor = Executors.newFixedThreadPool(5);
这样就创建了一个固定线程池大小为5的线程池。
- 提交任务
线程池创建完成后,我们需要向线程池中提交任务,执行相应的操作。通过submit()方法提交一个Callable或Runnable任务,可以异步执行,如下所示:
executor.submit(new Runnable() {
@Override
public void run() {
// do something
}
});
也可以提交一个带返回值的Callable任务:
Future<String> future = executor.submit(new Callable<String>() {
@Override
public String call() throws Exception {
return "Hello";
}
});
- 关闭线程池
当任务执行完成后,可以关闭线程池,释放相应的资源。可以使用shutdown()方法,如下所示:
executor.shutdown();
- 提交任务后获取结果
执行submit()方法后,可以获取任务的执行结果。如果是Runnable任务,没有返回值,即为null;如果是Callable任务,则可以使用Future对象获取返回值,如下所示:
Future<String> future = executor.submit(new Callable<String>() {
@Override
public String call() throws Exception {
return "Hello";
}
});
String result = future.get(); // 获取返回结果
三、示例说明
示例一
下面我们通过一个简单的示例来说明Executors类的使用。假设有10个任务需要在5个线程池中进行计算,每个任务耗时1秒。我们可以使用Executors类创建一个固定线程池大小为5的线程池进行计算,如下所示:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExecutorExample {
private static final int TASK_COUNT = 10;
public static void main(String[] args) {
// 创建固定大小的线程池
ExecutorService executor = Executors.newFixedThreadPool(5);
// 提交10个任务
for (int i = 1; i <= TASK_COUNT; i++) {
int taskId = i;
executor.submit(new Runnable() {
@Override
public void run() {
try {
// 模拟任务计算
System.out.println("Task[" + taskId + "] start");
Thread.sleep(1000);
System.out.println("Task[" + taskId + "] end");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
// 关闭线程池
executor.shutdown();
}
}
执行结果如下所示:
Task[1] start
Task[2] start
Task[3] start
Task[4] start
Task[5] start
Task[1] end
Task[6] start
Task[2] end
Task[7] start
Task[3] end
Task[8] start
Task[4] end
Task[9] start
Task[5] end
Task[10] start
Task[6] end
Task[7] end
Task[8] end
Task[9] end
Task[10] end
可以看到,我们创建了一个固定线程池大小为5的线程池,提交10个任务进行计算,任务被线程池中的5个线程依次执行,每个任务耗时1秒。
示例二
上面的示例中,我们只是简单地提交了10个简单的任务,通过线程池执行。下面我们通过一个更复杂的示例来说明Executors类的使用。假设有一个初始值为0的计数器,需要通过多线程来并发增加其值,增加的次数是10亿次。我们可以使用Executors类创建一个固定线程池大小为10的线程池进行并发增加,如下所示:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
public class ExecutorExample {
private static final int TASK_COUNT = 100;
private static final int INCREASE_COUNT = 10000000;
public static void main(String[] args) throws InterruptedException {
// 创建固定大小的线程池
ExecutorService executor = Executors.newFixedThreadPool(10);
// 使用AtomicLong保证线程安全
AtomicLong counter = new AtomicLong(0);
// 提交100个任务
for (int i = 0; i < TASK_COUNT; i++) {
executor.submit(new Runnable() {
@Override
public void run() {
long startTime = System.currentTimeMillis();
for (int j = 0; j < INCREASE_COUNT; j++) {
counter.incrementAndGet();
}
long endTime = System.currentTimeMillis();
System.out.println("Thread[" + Thread.currentThread().getName() + "] cost " + (endTime - startTime) + "ms.");
}
});
}
// 等待所有任务完成
executor.shutdown();
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
// 输出结果
System.out.println("Counter value: " + counter.get());
}
}
执行结果如下所示:
Thread[pool-1-thread-2] cost 1364ms.
Thread[pool-1-thread-3] cost 1368ms.
Thread[pool-1-thread-10] cost 1371ms.
Thread[pool-1-thread-9] cost 1384ms.
Thread[pool-1-thread-7] cost 1380ms.
Thread[pool-1-thread-5] cost 1380ms.
Thread[pool-1-thread-8] cost 1386ms.
Thread[pool-1-thread-1] cost 1394ms.
Thread[pool-1-thread-6] cost 1393ms.
Thread[pool-1-thread-4] cost 1405ms.
Counter value: 1000000000
可以看到,我们创建了一个固定线程池大小为10的线程池,并提交了100个任务进行并发计算,使用AtomicLong保证线程安全,最终输出了计算结果1亿。同时输出每个线程的计算时间,可以看到所有线程都是并发执行的。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java并发编程中使用Executors类创建和管理线程的用法 - Python技术站