java threadlocal 例子_在Java中分析ThreadLocal实例

3a231137b2e04c68665d1cd0d72cb023.png

在Java中分析ThreadLocal实例

从概念上理解threadlocal可以使变量与多个线程隔离,以实现线程安全. threadlocal打包的变量最终专用于每个相应的线程. 线程彼此独立. 一个具体的实现用于说明: <

public interface Consumer {

int consume();

}

public class ComsumeThread implements Runnable {

private Consumer consumer;

public ComsumeThread(Consumer consumer) {

this.consumer = consumer;

}

@Override

public void run() {

for(int i=0;i<10;i++){

System.out.println(Thread.currentThread().getName()+" After Consume left:"+consumer.consume());

}

}

}

public class ConsumeClientA implements Consumer {

private static int leftNum = 30;

@Override

public int consume() {

int orgLeftNum = leftNum;

Random random = new Random(System.currentTimeMillis());

try {

Thread.sleep(random.nextInt(3));

} catch (InterruptedException e) {

e.printStackTrace();

}

orgLeftNum = orgLeftNum -1;

leftNum = orgLeftNum;

return leftNum;

}

public static void main(String[] args){

Consumer consumer = new ConsumeClientA();

Thread thread1 = new Thread(new ComsumeThread(consumer));

Thread thread2 = new Thread(new ComsumeThread(consumer));

Thread thread3 = new Thread(new ComsumeThread(consumer));

thread1.start();

thread2.start();

thread3.start();

}

}

ConsumeClientA没有进行任何线程安全的处理,结果如下:

75bcfecbcabb514ef217d567c5729bbc.png

Thread-2 After Consume left:29

Thread-1 After Consume left:29

Thread-3 After Consume left:29

Thread-2 After Consume left:28

Thread-1 After Consume left:28

Thread-3 After Consume left:28

Thread-2 After Consume left:27

Thread-1 After Consume left:27

Thread-2 After Consume left:26

Thread-3 After Consume left:27

Thread-1 After Consume left:25

Thread-2 After Consume left:25

Thread-3 After Consume left:25

Thread-1 After Consume left:24

Thread-2 After Consume left:24

Thread-3 After Consume left:24

Thread-1 After Consume left:23

Thread-2 After Consume left:23

Thread-3 After Consume left:23

Thread-1 After Consume left:22

Thread-2 After Consume left:22

Thread-3 After Consume left:22

Thread-1 After Consume left:21

Thread-2 After Consume left:21

Thread-3 After Consume left:21

Thread-1 After Consume left:20

Thread-2 After Consume left:20

Thread-3 After Consume left:20

Thread-1 After Consume left:19

Thread-3 After Consume left:18

添加线程本地处理,每个线程彼此独立,实现如下:

public class ConsumeClientB implements Consumer {

private ThreadLocal leftNumThreadLocal = new ThreadLocal(){

@Override

protected Integer initialValue() {

return 30;

}

};

@Override

public int consume() {

int orgLeftNum = leftNumThreadLocal.get();

Random random = new Random(System.currentTimeMillis());

try {

Thread.sleep(random.nextInt(3));

} catch (InterruptedException e) {

e.printStackTrace();

}

orgLeftNum = orgLeftNum -1;

leftNumThreadLocal.set(orgLeftNum);

return leftNumThreadLocal.get();

}

public static void main(String[] args){

Consumer consumer = new ConsumeClientB();

Thread thread1 = new Thread(new ComsumeThread(consumer));

Thread thread2 = new Thread(new ComsumeThread(consumer));

Thread thread3 = new Thread(new ComsumeThread(consumer));

thread1.start();

thread2.start();

thread3.start();

}

}

操作结果如下:

b8485cb86dde2907966174ff15a3d0e5.png

Thread-1 After Consume left:29

Thread-3 After Consume left:29

Thread-2 After Consume left:29

Thread-1 After Consume left:28

Thread-3 After Consume left:28

Thread-2 After Consume left:28

Thread-1 After Consume left:27

Thread-3 After Consume left:27

Thread-2 After Consume left:27

Thread-1 After Consume left:26

Thread-3 After Consume left:26

Thread-2 After Consume left:26

Thread-1 After Consume left:25

Thread-3 After Consume left:25

Thread-2 After Consume left:25

Thread-1 After Consume left:24

Thread-3 After Consume left:24

Thread-2 After Consume left:24

Thread-1 After Consume left:23

Thread-3 After Consume left:23

Thread-2 After Consume left:23

Thread-1 After Consume left:22

Thread-3 After Consume left:22

Thread-2 After Consume left:22

Thread-1 After Consume left:21

Thread-3 After Consume left:21

Thread-2 After Consume left:21

Thread-1 After Consume left:20

Thread-3 After Consume left:20

Thread-2 After Consume left:20

每个线程都有自己的独立变量threadlocal使用实例,将它们彼此隔离以实现线程安全.

ThreadLocal如何实现这种线程隔离和线程安全性?

从ThreadLocal源代码可以看出,线程隔离和线程挂钩实际上是ThreadLocal.ThreadLocalMap的实现类. 最明显的体现是,这样的Thread源代码变量声明表明ThreadLocal.ThreadLocalMap和Thread Relationships:

20181011162459175183.png

ThreadLocal.ThreadLocalMap threadLocals, inheritableThreadLocals;

Thread类包含threadLocals对象. ThreadLocal的具体实现是根据提供的get,set和其他接口,对当前线程的threadLocals变量执行相关操作,例如以下get操作代码:

public T get() {

Thread t = Thread.currentThread();

ThreadLocalMap map = getMap(t);

if (map != null) {

ThreadLocalMap.Entry e = map.getEntry(this);

if (e != null)

return (T)e.value;

}

return setInitialValue();

}

ThreadLocal.ThreadLocalMap getMap(Thread t) {

return t.threadLocals;

}

如您所见,getMap()方法是从当前线程获取相应的threadLocals变量,然后从ThreadLocal.ThreadLocalMap类型的threadLocals变量获取与相应线程中的ThreadLocal对象相对应的变量值.

20200331012359244078.png

set方法的操作相同:

public void set(T value) {

Thread t = Thread.currentThread();

ThreadLocal.ThreadLocalMap map = getMap(t);

if(map != null) {

map.set(this, value);

} else {

this.createMap(t, value);

}

}

void createMap(Thread t, T firstValue) {

t.threadLocals = new ThreadLocalMap(this, firstValue);

}

static class Entry extends WeakReference {

Object value;

Entry(ThreadLocal var1, Object var2) {

super(var1);

this.value = var2;

}

}

在ThreadLocalMap中,有一个内部类Entry数组. 条目继承WeakReference实现. WeakReference的优点是保存对象引用,而不会干扰GC回收的对象. 当线程完成对threadLocals变量的回收后,Entry将不会对其进行封装. 变量的干扰.

并且ThreadLocalMap中的键是ThreadLocal,因此ThreadLocal对象只能将ThreadLocal值保存在Thread对象中.

总而言之threadlocal使用实例,很说ThreadLocal的实现是一种映射结构,将Thread对象存储为键,将变量存储为ThreadLocalMap中的值,这实际上是错误的.

本文来自电脑杂谈,转载请注明本文网址:

http://www.pc-fly.com/a/jisuanjixue/article-269085-1.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ThreadLocal是一种特殊的变量存储类,它允许每个线程拥有自己的副本变量,从而避免了线程之间的共享变量冲突。在JavaThreadLocal通常用于存储线程局部数据,即每个线程都有自己的数据副本,而不会受到其他线程的影响。 要使用ThreadLocal,首先需要创建一个ThreadLocal对象,并使用其set()方法将数据存储在当前线程的副本。例如: ```java ThreadLocal<Integer> threadLocal = new ThreadLocal<>(); threadLocal.set(42); ``` 在这个例子,我们创建了一个ThreadLocal对象threadLocal,并将其初始化为空值。然后,我们使用set()方法将整数值42存储在当前线程的副本。 接下来,我们可以通过get()方法从当前线程获取存储在该ThreadLocal对象的值。例如: ```java int value = threadLocal.get(); ``` 这个例子,我们从当前线程的副本获取了存储在threadLocal的值,并将其存储在变量value。由于每个线程都有自己的副本,因此我们可以通过这种方式在不同的线程之间传递数据。 需要注意的是,ThreadLocal的数据存储在每个线程的本地内存,因此如果一个线程修改了存储在ThreadLocal的值,它不会影响其他线程的副本。这意味着ThreadLocal通常用于存储需要在多个线程之间隔离的数据。 除了set()和get()方法外,ThreadLocal还提供了remove()方法来删除当前线程的数据副本。此外,还可以使用getAndSet()方法来获取当前线程的值并设置新的值。 总之,ThreadLocal是一种非常有用的工具,它允许每个线程拥有自己的数据副本,从而避免了共享变量之间的冲突。它通常用于需要隔离不同线程之间的数据的情况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值