ThreadLocal 使用及原理

当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。这样就隔离了多个线程对数据的数据共享

[color=red]当线程并发时,使用ThreadLocal在保证每个线程拥有自己的独立对象,线程间互不影响。[/color]

原理:
ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很简单:在ThreadLocal类中有一个Map,用于存储每一个线程的变量副本,Map中元素的键为线程对象,而值对应线程的变量副本。我们自己就可以提供一个简单的实现版本:

区别:
ThreadLocal和Synchonized都用于解决多线程并发访问。但是ThreadLocal与synchronized有本质的区别。synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享。

使用:
public class MyThreadLocal {
//定义了一个ThreadLocal变量,用来保存int或Integer数据
private ThreadLocal<Integer> tl = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return 0;
}
};

public Integer getNextNum() {
//将tl的值获取后加1,并更新设置t1的值
tl.set(tl.get() + 1);
return tl.get();
}
}

* 测试线程
*/
public class TestThread extends Thread {
private MyThreadLocal tlt = new MyThreadLocal();

public TestThread(MyThreadLocal tlt) {
this.tlt = tlt;
}

@Override
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + tlt.getNextNum());
}
}
}

public class Test {
public static void main(String[] args) {
MyThreadLocal tlt = new MyThreadLocal();
Thread t1 = new TestThread(tlt);
Thread t2 = new TestThread(tlt);
Thread t3 = new TestThread(tlt);
Thread t4 = new TestThread(tlt);
t1.start();
t2.start();
t3.start();
t4.start();

}
}

可以看出,三个线程各自独立编号,互不影响:
Thread-0 1
Thread-1 1
Thread-0 2
Thread-1 2
Thread-0 3
Thread-1 3
Thread-2 1
Thread-3 1
Thread-2 2
Thread-3 2
Thread-2 3
Thread-3 3


Process finished with exit code 0


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
private static ThreadLocal DATE_FORMAT_NUM = new ThreadLocal() {
protected synchronized SimpleDateFormat initialValue() {
return new SimpleDateFormat("yyyyMMddHHmmss");
}
};
ThreadLocal是Java的一个线程级别的变量,它提供了一种简单的方式来在多线程环境维护变量的值。每个线程都拥有自己独立的ThreadLocal实例,并且可以通过该实例来获取和设置其对应的变量的值。 ThreadLocal原理是通过在每个线程创建一个独立的副本来存储变量的值。这样,每个线程都可以独立地访问和修改自己的副本,而不会对其他线程产生影响。 ThreadLocal使用非常简单。首先,我们需要创建一个ThreadLocal对象,并指定要存储的变量类型。然后,我们可以通过调用ThreadLocal的get方法来获取当前线程与该ThreadLocal对象关联的变量值,如果当前线程还没有设置过该变量,get方法会返回null。类似地,我们可以通过调用ThreadLocal的set方法来设置当前线程与该ThreadLocal对象关联的变量值。 下面是一个简单的示例代码: ``` public class ThreadLocalExample { private static final ThreadLocal<String> THREAD_LOCAL = new ThreadLocal<>(); public static void main(String[] args) { THREAD_LOCAL.set("Hello, world!"); Thread thread1 = new Thread(() -> { THREAD_LOCAL.set("Hello from thread 1!"); System.out.println(THREAD_LOCAL.get()); }); Thread thread2 = new Thread(() -> { THREAD_LOCAL.set("Hello from thread 2!"); System.out.println(THREAD_LOCAL.get()); }); thread1.start(); thread2.start(); System.out.println(THREAD_LOCAL.get()); } } ``` 在上面的示例,我们创建了一个ThreadLocal对象`THREAD_LOCAL`用于存储String类型的变量。首先我们通过调用`THREAD_LOCAL.set("Hello, world!")`方法在主线程设置了变量的值。然后,我们创建了两个新的线程并分别在其设置了不同的值,并打印出来。最后,在主线程我们也打印了变量的值。 运行上面的代码,你会看到输出结果类似于: ``` Hello from thread 1! Hello from thread 2! Hello, world! ``` 可以看到,每个线程都可以独立地访问和修改自己的变量副本,不会对其他线程产生影响。这样就确保了在多线程环境,每个线程都可以维护自己的变量状态。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值