③ 1000个线程格式化
然而当我们将线程的数量从 10 个变成 1000 个的时候,我们就不能单纯的使用 for
循环来创建 1000 个线程的方式来解决问题了,因为这样频繁的新建和销毁线程会造成大量的系统开销和线程过度争抢 CPU
资源的问题。
所以经过一番思考后,我们决定使用线程池来执行这 1000 次的任务,因为线程池可以复用线程资源,无需频繁的新建和销毁线程,也可以通过控制线程池中线程的数量来避免过多线程所导致的 CPU
资源过度争抢和线程频繁切换所造成的性能问题,而且我们可以将 SimpleDateFormat
提升为全局变量,从而避免每次执行都要新建 SimpleDateFormat
的问题,于是我们写下了这样的代码:
import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; publicclass App { // 时间格式化对象 privatestatic SimpleDateFormat simpleDateFormat = new SimpleDateFormat("mm:ss"); public static void main(String[] args) throws InterruptedException { // 创建线程池执行任务 ThreadPoolExecutor threadPool = new ThreadPoolExecutor(10, 10, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1000)); for (int i = 0; i < 1000; i++) { int finalI = i; // 执行任务 threadPool.execute(new Runnable() { @Override public void run() { // 得到时间对象 Date date = new Date(finalI * 1000); // 执行时间格式化 formatAndPrint(date); } }); } // 线程池执行完任务之后关闭 threadPool.shutdown(); } /** * 格式化并打印时间 * @param date 时间对象 */ private static void formatAndPrint(Date date) { // 执行格式化 String result = simpleDateFormat.format(date); // 打印最终结果 System.out.println("时间:" + result); } }
以上程序的执行结果为:
当我们怀着无比喜悦的心情去运行程序的时候,却发现意外发生了,这样写代码竟然会出现线程安全的问题。从上述结果可以看出,程序的打印结果竟然有重复内容的,正确的情况应该是没有重复的时间才对。
PS:所谓的线程安全问题是指:在多线程的执行中,程序的执行结果与预期结果不相符的情况。