在做ThreadLocal时遇到了一件特别郁闷的事。因为ThreadLocal是线程独享的,但是我在做程序开发时却遇到一个问题,就是ThreadLocal里总是有另外一个线程插入的数据。最后终于发现,原来启动的两个线程都是main线程,不知道为什么。。。。。。。。。
clean项目,重启MyEclipse后,问题解决了。。。。。。。。。。
紧接着又一件郁闷事来了。在使用线程池时,如果某一个线路中运行含有ThreadLocal变量时,当将这个线程释放回线程池时,再次取出后,这时的ThreadLocal还会保存上次运行时的结果,而不会重置线程。所以我的程序出现有时正确、有时错误的状态。。。。。。。
来看一个实例:
- public class SequenceNumber {
- // overwrite the ThreadLocal method initialValue() to set a initial value
- private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>() {
- public Integer initialValue() {
- return 0;
- }
- };
- // get next number
- public int getNextNum() {
- seqNum.set(seqNum.get() + 1);
- return seqNum.get();
- }
- public static void main(String[] args) {
- SequenceNumber sn = new SequenceNumber();
- // 3 threads use the same number variable and increase it
- TestClient t1 = new TestClient(sn);
- TestClient t2 = new TestClient(sn);
- TestClient t3 = new TestClient(sn);
- t1.start();
- t2.start();
- t3.start();
- }
- private static class TestClient extends Thread {
- private SequenceNumber sn;
- public TestClient(SequenceNumber sn) {
- this.sn = sn;
- }
- public void run() {
- for (int i = 0; i < 3; i++) {
- // every thread print 3 number
- System.out.println("thread[" + Thread.currentThread().getName()
- + "] sn[" + sn.getNextNum() + "]");
- }
- }
- }
- }
public class SequenceNumber {
// overwrite the ThreadLocal method initialValue() to set a initial value
private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>() {
public Integer initialValue() {
return 0;
}
};
// get next number
public int getNextNum() {
seqNum.set(seqNum.get() + 1);
return seqNum.get();
}
public static void main(String[] args) {
SequenceNumber sn = new SequenceNumber();
// 3 threads use the same number variable and increase it
TestClient t1 = new TestClient(sn);
TestClient t2 = new TestClient(sn);
TestClient t3 = new TestClient(sn);
t1.start();
t2.start();
t3.start();
}
private static class TestClient extends Thread {
private SequenceNumber sn;
public TestClient(SequenceNumber sn) {
this.sn = sn;
}
public void run() {
for (int i = 0; i < 3; i++) {
// every thread print 3 number
System.out.println("thread[" + Thread.currentThread().getName()
+ "] sn[" + sn.getNextNum() + "]");
}
}
}
}
运行的结果如下:
- thread[Thread-2] sn[1]
- thread[Thread-2] sn[2]
- thread[Thread-2] sn[3]
- thread[Thread-1] sn[1]
- thread[Thread-1] sn[2]
- thread[Thread-1] sn[3]
- thread[Thread-0] sn[1]
- thread[Thread-0] sn[2]
- thread[Thread-0] sn[3]
thread[Thread-2] sn[1]
thread[Thread-2] sn[2]
thread[Thread-2] sn[3]
thread[Thread-1] sn[1]
thread[Thread-1] sn[2]
thread[Thread-1] sn[3]
thread[Thread-0] sn[1]
thread[Thread-0] sn[2]
thread[Thread-0] sn[3]
如果两个线程要共享同一个变量,除了这个变量为静态变量外,还可以传递引用达到共享目的,如下:
- public class TestThreadLocal {
- public static void main(String[] args) throws InterruptedException {
- // 两个线程共享字符串常量
- String ss = "xx";
- // 两个线程共享引用类型变量
- List l = new ArrayList();
- l.add("xxx");
- // 两个线程共享引用变量
- ThreadLocal<List<String>> list = new ThreadLocal<List<String>>();
- list.set(new ArrayList<String>());
- new TestClient(ss,l,list).run();
- Thread.sleep(1000);
- System.out.println(ss + l +list.get());
- }
- private static class TestClient extends Thread {
- private String sn;
- private List p;
- private ThreadLocal<List<String>> li;
- public TestClient(String sn,List p,ThreadLocal<List<String>> li) {
- this.sn = sn;
- this.p = p;
- this.li = li;
- }
- public void run() {
- sn = "bbbbbbb";
- for (int i = 0; i < 3; i++) {
- p.add("xxxx-" + i);
- li.get().add("th+"+i);
- System.out.println(sn + p);
- }
- }
- }
- }
public class TestThreadLocal {
public static void main(String[] args) throws InterruptedException {
// 两个线程共享字符串常量
String ss = "xx";
// 两个线程共享引用类型变量
List l = new ArrayList();
l.add("xxx");
// 两个线程共享引用变量
ThreadLocal<List<String>> list = new ThreadLocal<List<String>>();
list.set(new ArrayList<String>());
new TestClient(ss,l,list).run();
Thread.sleep(1000);
System.out.println(ss + l +list.get());
}
private static class TestClient extends Thread {
private String sn;
private List p;
private ThreadLocal<List<String>> li;
public TestClient(String sn,List p,ThreadLocal<List<String>> li) {
this.sn = sn;
this.p = p;
this.li = li;
}
public void run() {
sn = "bbbbbbb";
for (int i = 0; i < 3; i++) {
p.add("xxxx-" + i);
li.get().add("th+"+i);
System.out.println(sn + p);
}
}
}
}
最后运行的结果如下:
- bbbbbbb[xxx, xxxx-0]
- bbbbbbb[xxx, xxxx-0, xxxx-1]
- bbbbbbb[xxx, xxxx-0, xxxx-1, xxxx-2]
- xx[xxx, xxxx-0, xxxx-1, xxxx-2][th+0, th+1, th+2]
bbbbbbb[xxx, xxxx-0]
bbbbbbb[xxx, xxxx-0, xxxx-1]
bbbbbbb[xxx, xxxx-0, xxxx-1, xxxx-2]
xx[xxx, xxxx-0, xxxx-1, xxxx-2][th+0, th+1, th+2]
再来看一个例子,如下:
- public class AbstractA {
- public void init(){
- List<String> l = new ArrayList<String>();
- l.add("张三");
- l.add("李四");
- if(DataStore.getList().get()==null){
- DataStore.getList().set(l);
- }
- }
- }
public class AbstractA {
public void init(){
List<String> l = new ArrayList<String>();
l.add("张三");
l.add("李四");
if(DataStore.getList().get()==null){
DataStore.getList().set(l);
}
}
}
- public class ClassicB extends AbstractA{
- public void b() {
- init();
- DataStore.getList().get().add("a");
- DataStore.getList().get().add("b");
- // 打印结果
- System.out.println(DataStore.getList().get());
- }
- }
public class ClassicB extends AbstractA{
public void b() {
init();
DataStore.getList().get().add("a");
DataStore.getList().get().add("b");
// 打印结果
System.out.println(DataStore.getList().get());
}
}
- public class Main {
- static ClassicB b = new ClassicB();
- public static void main(String[] args) {
- b.b();
- b.b();
- new SynchronizedTask().start();
- new SynchronizedTask().start();
- }
- private static class SynchronizedTask extends Thread {
- public void run() {
- b.b();
- }
- }
- }
public class Main {
static ClassicB b = new ClassicB();
public static void main(String[] args) {
b.b();
b.b();
new SynchronizedTask().start();
new SynchronizedTask().start();
}
private static class SynchronizedTask extends Thread {
public void run() {
b.b();
}
}
}
最终运行的结果如下:
[张三, 李四, a, b]
[张三, 李四, a, b, a, b]
[张三, 李四, a, b]
[张三, 李四, a, b]
可以看到ThreadLocal是每个线程独享的。