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的源代码。
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的源代码。
相关文章推荐
- 后缀自动机的直观理解
- 分享 转--对ThreadLocal理解
- Java并发编程--理解ThreadLocal
- 深入理解线程局部变量:ThreadLocal
- 关于ThreadLocal的理解
- 理解ThreadLocal
- Machine Learning(Stanford)| 斯坦福大学机器学习笔记--第一周(3.代价函数直观理解)
- 通过一堂化学课来彻底理解 ThreadLocal
- 彻底理解ThreadLocal(转)
- 深入学习理解java-ThreadLocal
- 彻底理解ThreadLocal
- 理解java.lang.ThreadLocal 类
- 【Java】深入理解ThreadLocal
- 正确理解ThreadLocal[转]
- 理解ThreadLocal
- WPF几个基础概念的浅显理解
- 彻底理解ThreadLocal
- 彻底理解ThreadLocal
- 彻底理解ThreadLocal
- 彻底理解ThreadLocal