ThreadLocal 初试

ThreadLocal 学习一下

之前就接触过好多次这个类,一直没搞明白这货是啥,怎么个用法,今天仔细研究一下,原来用法很简单;
只是没有使用场景,学的容易忘的更容易罢了,记录一下,以作备忘;

ThreadLocal到底是什么?

字面意思好像是本地线程,不太贴切,并不是一个线程, “线程本地变量表”更合适一些,就是用来存储线程私有的变量;
大家都知道,一个类,如果有属性,不加同步控制的话,并发访问的情况下,结果是不可预测的,数据会在多个线程之间窜,ThreadLocal解决了这个问题;

ThreadLocal为每一个使用该变量的线程都提供一个变量值的副本,是Java中一种较为特殊的线程绑定机制,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。

OK,现在清楚了,辣么使用场景也就知道了:让我们可以在多线程环境下不用加锁,而又能安全的访问公共对象的属性;

前辈告诉我们,能用代码解决的问题就不要讲道理,那么上栗子:
首先看看不使用ThreadLocal, 定义一个Runnable,她有一个属性:

package net.tt.web.stu.concurrent.threadlocal;

import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author tbc
 * @version 1.0 {2016年6月16日 下午3:42:29}
 */
public class NoThreadLocal implements Runnable {
    private Logger log = LoggerFactory.getLogger(NoThreadLocal.class);

    private String str = new String("str");

    @Override
    public void run() {
        // 先读取
        log.info("one -> Trhead: {}, var: {}", Thread.currentThread().getName(), str);
        // 再写入
        str = Thread.currentThread().getName();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 再读取
        log.info("two -> Trhead: {}, var: {}", Thread.currentThread().getName(), str);
    }

    public static void main(String[] args) {
        NoThreadLocal t = new NoThreadLocal();
        new Thread(t, "a").start();
        new Thread(t, "b").start();
        new Thread(t, "c").start();
    }

}

我们实例化一个此类的对象,然后起多个线程去调用,很明显,结果是不可预知的:
ThreadLocal 初试_第1张图片

乱了,每个线程拿到的值都是a,怎么办呢?当然可以加锁:

    public synchronized void setStr(String str) {
        this.str = str;
    }

如果不想加锁呢?这个时候ThreadLocal 可以出场 :

package net.tt.web.stu.concurrent.threadlocal;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author tbc
 * @version 1.0 {2016年6月16日 下午3:30:39}
 */
public class ThreadLocalTest implements Runnable {
    private Logger log = LoggerFactory.getLogger(ThreadLocalTest.class);

    private static final ThreadLocal var = new ThreadLocal();

    @Override
    public void run() {
        // 先读取
        log.info("one -> Trhead: {}, var: {}", Thread.currentThread().getName(), getThreadLocal().get());
        // 再写入
        var.set(Thread.currentThread().getName());
        // 停一下等其它线程跑偏
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 再读取
        log.info("two -> Trhead: {}, var: {}", Thread.currentThread().getName(), getThreadLocal().get());
    }

    public ThreadLocal getThreadLocal() {
        String a = var.get();
        if (a == null) {
            var.set("init");
        }
        return var;
    }

    public static void main(String[] args) {
        ThreadLocalTest t = new ThreadLocalTest();
        new Thread(t, "a").start();
        new Thread(t, "b").start();
        new Thread(t, "c").start();
    }

}

现在就好了,我们的目的达到了:
ThreadLocal 初试_第2张图片

perfect!

你可能感兴趣的:(java)