高并发--卷3--ThreadLocal

在java并发编程中,经常用到ThreadLocal来保存一个变量的值,而且,不同线程直接存放的数据具有隔离性。

ThreadLocal-set(T)/get()

通过set(T)和get()进行存值和取值,不同线程之间具有隔离性。


public class T{
    public static ThreadLocal<String> tl = new ThreadLocal<String>();
    public static void main(String[] args) {
        if(tl.get() == null){
            tl.set("main value");
        }
        new Thread(new MyThread()).start();
        System.out.println(T.tl.get());
    }
}

class MyThread implements Runnable{
    @Override
    public void run() {
        if(T.tl.get() == null){
            T.tl.set(Thread.currentThread().getName());
        }
        System.out.println(T.tl.get());
    }   
}

main value
Thread-0

ThreadLocal的initialValue()方法

如果在ThreadLocal的子类中使用initialValue()方法,那么new出的子类就要会直接使用该构造的值。也就是说,不进行set()也能直接通过get()提取到初始值。

public class T{
    public static MyThreadLocal tl = new MyThreadLocal();
    public static void main(String[] args) {
        System.out.println(T.tl.get());
        new Thread(new Mythread()).start();
    }
}

class MyThreadLocal extends ThreadLocal<String>{
    @Override
    protected String initialValue() {    
        return "ThreadLocal的初始值";
    }   
}

class Mythread implements Runnable{
    @Override
    public void run() {
        System.out.println(T.tl.get());;
    }

}

ThreadLocal的初始值
ThreadLocal的初始值

继承父线程的ThreadLocal的值

有时候,需要让子线程继承父线程的某个值,这里的父子关系不是通过extends产生的父子关系,而是子线程在父线程启动产生的父子关系,举个例子,比如让t1在main线程只中启动,那么t1就是main线程的子线程。


public class T{
    public static MyThreadLocal tl = new MyThreadLocal();
    public static void main(String[] args) {
        T.tl.set("asd");
        System.out.println(T.tl.get());
        new Thread(new Mythread()).start();
    }
}

class MyThreadLocal extends InheritableThreadLocal<String>{
    @Override
    protected String initialValue() {
        return "ThreadLocal的初始值";
    }   
    /*
    @Override
    protected String childValue(String parentValue) {
        return "child中的值";
    }
    */
}

class Mythread implements Runnable{
    @Override
    public void run() {
        System.out.println(T.tl.get());;
    }
}

asd
asd

你会发现,在main中修改了ThreadLocal中的值后,子线程中的值也会随着改变,当然,如果你的修改在子线程启动之后才完成的,那么这个值将不会影响到子线程的ThreadLocal中的值。

childValue()

如果希望子线中的子不继承于父线程,而使用指定的值,那么这里应该使用childValue()方法来实现对子线程值的ThreadLocal中的值进行初始化。


public class T{
    public static MyThreadLocal tl = new MyThreadLocal();
    public static void main(String[] args) {
        T.tl.set("asd");
        System.out.println(T.tl.get());
        new Thread(new Mythread()).start();
    }
}

class MyThreadLocal extends InheritableThreadLocal<String>{
    @Override
    protected String initialValue() {
        return "ThreadLocal的初始值";
    }   
    @Override
    protected String childValue(String parentValue) {
        return "child中的值";
    }
}

class Mythread implements Runnable{
    @Override
    public void run() {
        System.out.println(T.tl.get());;
    }
}

输出结果:
asd
child中的值

ThreadLocal的应用场景

在Spring中,dao和service都是单例,当多个用户并发的时候,可能产生多个连接,所以,有的读者认为,dao不应该是单例,但事实上在Spring容器中,dao确实是单例,那么他是如何实现一个单例保存多个connection的呢?实际上,Spring就是用到了ThreadLocal。下面来看一下它的实现方式。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;


public class T{
    private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
    public static Connection getConnection() throws ClassNotFoundException, SQLException{
        Connection connection = tl.get();
        if(connection == null){
            Class.forName("com.mysql.jdbc.Driver");
            String url = "";
            String username = "";
            String password = "";
            connection = DriverManager.getConnection(url,username,password);
            tl.set(connection);
        }
        return connection;  
    }
}

在单例模式下,不同线程都可以通过ThreadLocal能获取到自身的Connection。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值