美文网首页
ThreadLocal的使用

ThreadLocal的使用

作者: 文景大大 | 来源:发表于2020-04-29 20:01 被阅读0次

    一、为什么要使用

    我们在先前的文章《synchronized关键字使用详解》中曾经介绍过,什么场景下不需要考虑线程安全的问题,其中一种场景就是“变量为线程独享变量的时候”,当时的例子如下:

    @Slf4j
    public class MyThread implements Runnable {
        // 线程独享的变量
        private int count = 200;
    
        @Override
        public void run() {
            count--;
            log.info("当前线程名称:{},计数器为:{}", Thread.currentThread().getName(), count);
        }
    }
    

    在这个例子中,我们的变量是在线程类中的,它并没有使用额外的特殊的修饰符,每启动一个线程,则每个线程都会有一个自己的变量实例,所以不涉及线程安全的问题。

    但是,如果这个变量是在线程需要使用的外部类中:

    @Slf4j
    public class Thread2 implements Runnable {
        @Override
        public void run() {
            while (Counter.counter > 0) {
                Counter.minus();
                log.info("{}当前a值为:{}", Thread.currentThread().getName(), Counter.counter);
            }
        }
    }
    
    public class Counter {
        public static int counter = 10;
    
        public static void minus(){
            count--;
        }
    }
    

    此时就会出现线程安全问题了,针对这种情况,我们如何使得每个线程单独保留一份自己的变量实例呢?

    主角ThreadLocal就该出现了。

    二、入门实例

    public class Counter {
        public static ThreadLocal<Integer> counter = new ThreadLocal<>();
    
        public static void initCounter(){
            counter.set(10);
        }
        public static void minus(){
            Integer cnt = counter.get();
            counter.set(--cnt);
        }
    }
    
    @Slf4j
    public class Thread2 implements Runnable {
        @Override
        public void run() {
            Counter.initCounter();
            while (Counter.counter.get() > 0) {
                Counter.minus();
                log.info("{}当前a值为:{}", Thread.currentThread().getName(), Counter.counter.get());
            }
        }
    }
    

    这个例子中,每个线程都会保留一份属于自己的变量,相互之间不共享。

    但是有一个问题,ThreadLocal变量声明后,默认get返回的是null,而不是0,我们有时候需要它能有默认值,那么就应该使用自定义的ThreadLocal类:

    public class ThreadLocalNew<T> extends ThreadLocal {
        @Override
        protected Object initialValue() {
            return 10;
        }
    }
    
    public class Counter {
        public static ThreadLocalNew<Integer> counter = new ThreadLocalNew<>();
    
        public static void minus(){
            Integer cnt = (Integer) counter.get();
            counter.set(--cnt);
        }
    }
    
    @Slf4j
    public class Thread2 implements Runnable {
    
        @Override
        public void run() {
            while ((Integer)Counter.counter.get() > 0) {
                Counter.minus();
                log.info("{}当前a值为:{}", Thread.currentThread().getName(), Counter.counter.get());
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:ThreadLocal的使用

          本文链接:https://www.haomeiwen.com/subject/gxvjwhtx.html