threadlocal用法示例,threadlocal使用场景

首页 > 技术 > 作者:YD1662023-04-15 23:54:10

1.ThreadLocal的使用场景

1.1 场景1

每个线程需要一个独享对象(通常是工具类,典型需要使用的类有SimpleDateFormat和Random)

每个Thread内有自己的实例副本,不共享

比喻:教材只有一本,一起做笔记有线程安全问题。复印后没有问题,使用ThradLocal相当于复印了教材。

1.2 场景2

每个线程内需要保存全局变量(例如在拦截器中获取用户信息),可以让不同方法直接使用,避免参数传递的麻烦

2.对以上场景的实践

2.1 实践场景1

/** * 两个线程打印日期 */ public class ThreadLocalNormalUsage00 { public static void main(String[] args) throws InterruptedException { new Thread(new Runnable() { @Override public void run() { String date = new ThreadLocalNormalUsage00().date(10); System.out.println(date); } }).start(); new Thread(new Runnable() { @Override public void run() { String date = new ThreadLocalNormalUsage00().date(104707); System.out.println(date); } }).start(); } public String date(int seconds) { //参数的单位是毫秒,从1970.1.1 00:00:00 GMT 开始计时 Date date = new Date(1000 * seconds); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); return dateFormat.format(date); } }

运行结果

threadlocal用法示例,threadlocal使用场景(1)

因为中国位于东八区,所以时间从1970年1月1日的8点开始计算的

/** * 三十个线程打印日期 */ public class ThreadLocalNormalUsage01 { public static void main(String[] args) throws InterruptedException { for (int i = 0; i < 30; i ) { int finalI = i; new Thread(new Runnable() { @Override public void run() { String date = new ThreadLocalNormalUsage01().date(finalI); System.out.println(date); } }).start(); //线程启动后,休眠100ms Thread.sleep(100); } } public String date(int seconds) { //参数的单位是毫秒,从1970.1.1 00:00:00 GMT 开始计时 Date date = new Date(1000 * seconds); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); return dateFormat.format(date); } }

运行结果

threadlocal用法示例,threadlocal使用场景(2)

多个线程打印自己的时间(如果线程超级多就会产生性能问题),所以要使用线程池。

/** * 1000个线程打印日期,用线程池来执行 */ public class ThreadLocalNormalUsage02 { public static ExecutorService threadPool = Executors.newFixedThreadPool(10); public static void main(String[] args) throws InterruptedException { for (int i = 0; i < 1000; i ) { int finalI = i; //提交任务 threadPool.submit(new Runnable() { @Override public void run() { String date = new ThreadLocalNormalUsage02().date(finalI); System.out.println(date); } }); } threadPool.shutdown(); } public String date(int seconds) { //参数的单位是毫秒,从1970.1.1 00:00:00 GMT 开始计时 Date date = new Date(1000 * seconds); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); return dateFormat.format(date); } }

运行结果

threadlocal用法示例,threadlocal使用场景(3)

但是使用线程池时就会发现每个线程都有一个自己的SimpleDateFormat对象,没有必要,所以将SimpleDateFormat声明为静态,保证只有一个

/** * 1000个线程打印日期,用线程池来执行,出现线程安全问题 */ public class ThreadLocalNormalUsage03 { public static ExecutorService threadPool = Executors.newFixedThreadPool(10); //只创建一次 SimpleDateFormat 对象,避免不必要的资源消耗 static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); public static void main(String[] args) throws InterruptedException { for (int i = 0; i < 1000; i ) { int finalI = i; //提交任务 threadPool.submit(new Runnable() { @Override public void run() { String date = new ThreadLocalNormalUsage03().date(finalI); System.out.println(date); } }); } threadPool.shutdown(); } public String date(int seconds) { //参数的单位是毫秒,从1970.1.1 00:00:00 GMT 开始计时 Date date = new Date(1000 * seconds); return dateFormat.format(date); } }

运行结果

出现了秒数相同的打印结果,这显然是不正确的。

threadlocal用法示例,threadlocal使用场景(4)

首页 1234下一页

栏目热文

文档排行

本站推荐

Copyright © 2018 - 2021 www.yd166.com., All Rights Reserved.