b) 解决线程安全问题:加锁
当出现线程安全问题时,我们想到的第一解决方案就是加锁,具体的实现代码如下:
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 = null; // 加锁 synchronized (App.class) { result = simpleDateFormat.format(date); } // 打印最终结果 System.out.println("时间:" + result); } }
以上程序的执行结果为:
从上述结果可以看出,使用了 synchronized
加锁之后程序就可以正常的执行了。
加锁的缺点
加锁的方式虽然可以解决线程安全的问题,但同时也带来了新的问题,当程序加锁之后,所有的线程必须排队执行某些业务才行,这样无形中就降低了程序的运行效率了。
有没有既能解决线程安全问题,又能提高程序的执行速度的解决方案呢?
答案是:有的,这个时候 ThreadLocal
就要上场了。