您的位置:首页 > 其它

ThreadLocal的直观浅显理解

2012-11-02 14:14 381 查看
在java中,如果某个对象是非线程安全的共享资源,在多线程环境下,如果不加任何限制,对该资源的访问会存在冲突问题。针对这个问题,有以下几种解决方案:

1.加synchronized关键字,这种做法会限制并发访问,影响效率;

2.使用ThreadLocal维护共享资源(变量),为每个使用共享资源(变量)的线程提供独立的变量副本,从而避免冲突问题。

下面先来看一个例子

*

*序列号产生类

*/

public class SequenceNumber {

//序列号变量

private int segNum=0;

//获取下一个序列值

public int getNextNum(){

return ++segNum;

}

}

/**

*

* 序列号产生线程

*/

public class TestClient extends Thread{

//序列号产生类对象

private SequenceNumber sn;

//构造函数

public TestClient(String name,SequenceNumber sn) {

super(name);

this.sn = sn;

}

public void run() {

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

//每个线程打出3个序列值

System.out.println(getName()+":sn--->" + sn.getNextNum());

}

}

}

/**

*

* 主方法类

*/

public class Main {

public static void main(String[] args) {

SequenceNumber sn = new SequenceNumber();

// 3个线程共享sn,各自产生序列号

TestClient t1 = new TestClient("A",sn);

TestClient t2 = new TestClient("B",sn);

TestClient t3 = new TestClient("C",sn);

t1.start();

t2.start();

t3.start();

}

}

运行主方法类,输出

A:sn--->1

A:sn--->2

A:sn--->3

B:sn--->4

B:sn--->5

B:sn--->6

C:sn--->7

C:sn--->8

C:sn--->9

下面修改一下SequenceNumber类的实现

*

*序列号产生类

*/

public class SequenceNumber {

//序列号变量,通过匿名内部类覆盖ThreadLocal的initialValue()方法,指定初始值

private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>() {

public Integer initialValue() {

return 0;

}

};

//获取下一个序列值

public int getNextNum() {

seqNum.set(seqNum.get() + 1);

return seqNum.get();

}

}

运行主方法类,输出

A:sn--->1

A:sn--->2

A:sn--->3

C:sn--->1

B:sn--->1

B:sn--->2

B:sn--->3

C:sn--->2

C:sn--->3

可见,将SequenceNumber类的seqNum变量由int类型换成自定义的ThreadLocal<Integer>类型后,各个线程之间操作该共享对象的变量就互不影响了。

具体原因可以看下ThreadLocal的源代码。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: