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()防止内存泄漏

 

 
posted @ 2023-05-15 15:40  杨吃羊  阅读(27)  评论(0)    收藏  举报