线程内数据共享(ThreadfLocal)

ThreadfLocal用于实现线程内的数据共享,多个模块在同一个线程中运行时要共享一份数据,而在另外线程中运行时又共享另外一份数据(如事务处理中数据库链接的共享,可以实现事务控制),static变量是在jvm里只有一份,无法达到每个线程内数据隔离的效果,而ThreadLocal则从另一个角度来解决多线程的并发导致的数据安全问题,ThreadLocal将需要保护的对象保存在了线程内部,从而不与其它线程分享,这种线程级隔离避免了线程并发访问问题。


因为每一个线程都独立拥有一个对象,该对象只能被自己访问到,从而也就没有必要对该对象的进行同步控制了。

在编写多线程代码时,可以把线程不安全的变量封装进ThreadLocal中,从而避开同步提高性能,当然,要视实际情况而定。


示例代码:

import java.util.Random;

class Student {
    String name;
    String getName() {
        return name;
    }
    void setName(String name) {
        this.name = name;
    }
}
class DataCenter {
    private static DataCenter instance = new DataCenter();
    static DataCenter getInstance() {
        return instance;
    }
    /**
     * 不同的线程虽然共享了同一个共享的studentThreadLocal,
     * 但是其值Student是保存在各个线程内部的是不共享的,这就是线程隔离效果
     */
    ThreadLocal<Student> studentThreadLocal = new ThreadLocal<Student>();// 第一个 ThreadLocal
    Student getStudent() {
        Student student = studentThreadLocal.get();
        if (student == null) {
            System.out.println("每个线程只会在此初始化一次,本次初始化线程:" + Thread.currentThread().getName());
            student = new Student();
            student.setName("姓名" + Thread.currentThread().getName());
            studentThreadLocal.set(student);
        }
        return student;
    }
}
class ThreadLocalTest extends Thread {
    @Override
    public void run() {
        String currentThreadName = Thread.currentThread().getName();
        for (int i = 1; i <= 3; i++) {
            try {Thread.sleep(new Random().nextInt(500));} catch (Exception e) {}
            Student student = DataCenter.getInstance().getStudent();
            System.out.println(currentThreadName + " 第" + i + "次获取姓名: " + student.getName());
        }
    }
}
public class Test {
    public static void main(String[] args) {
        new ThreadLocalTest().start();
        new ThreadLocalTest().start();
    }
}

输出:

每个线程只会在此初始化一次,本次初始化线程:Thread-1
Thread-1 第1次获取姓名: 姓名Thread-1
每个线程只会在此初始化一次,本次初始化线程:Thread-0
Thread-0 第1次获取姓名: 姓名Thread-0
Thread-0 第2次获取姓名: 姓名Thread-0
Thread-1 第2次获取姓名: 姓名Thread-1
Thread-0 第3次获取姓名: 姓名Thread-0
Thread-1 第3次获取姓名: 姓名Thread-1
可以看出,两个线程,一共只进行了两次对象创建,之后每个线程都只访问到自己之前创建的对象(同线程打印student.getName()相同)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值