0
点赞
收藏
分享

微信扫一扫

【Java多线程与并发库】6.ThreadLocal类及应用技巧


之前我们了解了实现线程范围内数据共享的机制,接下来我们
可以使用JDK5提供的ThreadLocal类,来实现线程范围内数据共享。

ThreadLocal类其实就类似于我们上一次创建的Map。

我们创建一个测试类,来使用ThreadLocal类实现线程范围内数据共享:
我们的类A和类B每次都从线程中获取data值打印,为了保证每次打印的数据是该线程的数据,
类A和类B的数据都从ThreadLocal中获取。

package cn.edu.hpu.test;

import java.util.Random;

public class ThreadTest7 {

private static Random dandom=new Random();
private static ThreadLocal<Integer> x=new ThreadLocal<Integer>();

public static void main(String[] args) {
for(int i=0;i<2;i++){
new Thread(new Runnable(){
public void run() {
int data=dandom.nextInt();
System.out.println(Thread.currentThread().getName()
+"放入数据:"+data);
x.set(data);
new A().get();
new B().get();
}

}).start();
}
}

static class A{
public void get(){
System.out.println("A 从"+Thread.currentThread().getName()
+"中取的数据:"+x.get());
}
}

static class B{
public void get(){
System.out.println("B 从"+Thread.currentThread().getName()
+"中取的数据:"+x.get());
}
}
}


结果:


【Java多线程与并发库】6.ThreadLocal类及应用技巧_Thread



实现了每个线程中的数据共享在每个线程自己的范围内。线程之间的数据不会混杂在一起。



如果有N个变量需要做到线程范围内数据共享,应该如何做到?


一个ThreadLocal只能放一个变量,我们可以使用多个ThreadLocal来实现,


如果共享的数据量过大,我们就把这些数据放在一个对象中,然后在ThreadLocal中


存储这一个对象。


package cn.edu.hpu.test;

import java.util.Random;

public class ThreadTest7 {

private static Random dandom=new Random();
private static ThreadLocal<MyThreadScopeData> MyThreadScopeData=new ThreadLocal<MyThreadScopeData>();

public static void main(String[] args) {
for(int i=0;i<2;i++){
new Thread(new Runnable(){
public void run() {
int data=dandom.nextInt();
System.out.println(Thread.currentThread().getName()
+"放入数据:"+data);
MyThreadScopeData ScopeData=new MyThreadScopeData();
ScopeData.setName("name"+data);
ScopeData.setAge(data);
MyThreadScopeData.set(ScopeData);
new A().get();
new B().get();
}

}).start();
}
}

static class A{
public void get(){
System.out.println("A 从"+Thread.currentThread().getName()
+"中取的数据:"+MyThreadScopeData.get().getName()
+MyThreadScopeData.get().getAge());
}
}

static class B{
public void get(){
System.out.println("A 从"+Thread.currentThread().getName()
+"中取的数据:"+MyThreadScopeData.get().getName()
+MyThreadScopeData.get().getAge());
}
}
}

class MyThreadScopeData{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}


结果:


【Java多线程与并发库】6.ThreadLocal类及应用技巧_Thread_02



这样就可以在线程范围内共享N中数据了。



上面的设计其实不够好,但是要设计更加优雅一点,不要看到我们使用ThreadLocal的痕迹:


package cn.edu.hpu.test;

import java.util.Random;

public class ThreadTest7 {

private static Random dandom=new Random();
public static void main(String[] args) {
for(int i=0;i<2;i++){
new Thread(new Runnable(){
public void run() {
int data=dandom.nextInt();
System.out.println(Thread.currentThread().getName()
+"放入数据:"+data);

MyThreadScopeData.getThreadInstance().setName("name"+data);
MyThreadScopeData.getThreadInstance().setAge(data);
new A().get();
new B().get();
}

}).start();
}
}

static class A{
public void get(){
System.out.println("A 从"+Thread.currentThread().getName()
+"中取的数据:"+MyThreadScopeData.getThreadInstance().getName()
+MyThreadScopeData.getThreadInstance().getAge());
}
}

static class B{
public void get(){
System.out.println("A 从"+Thread.currentThread().getName()
+"中取的数据:"+MyThreadScopeData.getThreadInstance().getName()
+MyThreadScopeData.getThreadInstance().getAge());
}
}
}

class MyThreadScopeData{

private MyThreadScopeData(){}
public static MyThreadScopeData getThreadInstance(){
MyThreadScopeData instance=map.get();
if(instance==null){
instance=new MyThreadScopeData();
map.set(instance);
}
return instance;
}
private static ThreadLocal<MyThreadScopeData> map =new ThreadLocal<MyThreadScopeData>();

private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}


这里,我们调用MyThreadScopeData的getThreadInstance方法,就可以取得


与当前线程相关的实例对象。



虽然线程结束后也可以自动释放相关的ThreadLocal变量,但是为了优化内存,


我们的ThreadLocal要在线程结束的时候注销,可以调用ThreadLocal.clear()方法。


​​​


举报

相关推荐

0 条评论