threadlocal使用场景
多线程修改同一个变量造成线程间数据错乱示例
public class Demo { private String content; public String getContent() { return content; } public void setContent(String content) { this.content = content; } public static void main(String[] args) { Demo demo = new Demo(); for(int i = 0; i < 5;i++){ Thread thread = new Thread(()->{ demo.setContent(Thread.currentThread().getName()+"的数据"); //1 System.out.println("______________________________________"); //2 System.out.println(Thread.currentThread().getName()+"---->"+demo.getContent()); //3 }); thread.setName("线程"+i); thread.start(); } } }
输出结果:
______________________________________
______________________________________
______________________________________
______________________________________
线程0---->线程2的数据
______________________________________
线程1---->线程0的数据
线程3---->线程4的数据
线程4---->线程4的数据
线程2---->线程4的数据
造成这种现象的原因:线程1执行到第二行cpu执行线程切换到线程2,线程2将demo的content设为’线程2的数据‘,还没执行第三行又发生线程切换到线程1,线程1直接从
第三行执行,就会输出线程1---->线程2的数据
用threadlocal使线程之间变量不错乱示例
public class Demo { ThreadLocal<String> threadLocal = new ThreadLocal<>(); public String getContent() { return threadLocal.get(); } public void setContent(String content) { threadLocal.set(content); } public static void main(String[] args) { Demo demo = new Demo(); for(int i = 0; i < 5;i++){ Thread thread = new Thread(()->{ demo.setContent(Thread.currentThread().getName()+"的数据"); System.out.println("______________________________________"); System.out.println(Thread.currentThread().getName()+"---->"+demo.getContent()); }); thread.setName("线程"+i); thread.start(); } } }
线程1---->线程1的数据
线程3---->线程3的数据
线程4---->线程4的数据
线程0---->线程0的数据
线程2---->线程2的数据
用synchronized解决错乱问题示例
public class Demo { private String content; public String getContent() { return content; } public void setContent(String content) { this.content = content; } public static void main(String[] args) { Demo demo = new Demo(); for(int i = 0; i < 5;i++){ Thread thread = new Thread(()->{ synchronized (Demo.class) { demo.setContent(Thread.currentThread().getName()+"的数据"); System.out.println("______________________________________"); System.out.println(Thread.currentThread().getName()+"---->"+demo.getContent()); } }); thread.setName("线程"+i); thread.start(); } } }
______________________________________
线程0---->线程0的数据
______________________________________
线程4---->线程4的数据
______________________________________
线程3---->线程3的数据
______________________________________
线程2---->线程2的数据
______________________________________
线程1---->线程1的数据
锁住关键三行代码防止发生线程切换
用threadlocal和synchronized 都能解决多线程修改同一个变量造成的错乱问题,但这两种方案解决问题的本质不同,threadlocal是给每个线程创建一个
副本,防止多线程修改同一个变量,synchronized 是加锁使多线程排队访问变量。
1 threadlocal是map键值对,key是当前线程,value是自己设置的值.
2 在拦截器中将用户信息放到threadlocal中,后续业务方法直接从threadlocal中获取,这样做可以简化用户信息在方法间来回传递,在拦截器中配置方法结束后remove()掉threadlocal里的值. threadlocal也常用于声明式事务中service层向dao层传递connection(也可以用方法参数传递),注解式事务就是将connection放到threadlocal中保证多个dao之间用的是同一个connection.
注意:使用完threadlocal后要调用remove()防止内存泄漏
浙公网安备 33010602011771号