
本文主要介绍如何解决非线程安全问题. 多亏了Java Multithreading Core Programming这本书,它为该系列文章提供了参考.
变量值的共享可以采用公共静态变量的形式. 所有线程都使用相同的公共静态变量. 如果您想认识到每个线程都有自己的共享变量,该怎么办? JDK中提供的ThreadLocal类是为解决此类问题而正式设计的.
ThreadLocal类的主要解决方案是将每个线程绑定到自己的线程. 可以将ThreadLocal类比作一个用于全局存储数据的框多线程编程,每个线程的私有数据都可以存储在框中.
例如:

public class ThreadMain {
public static ThreadLocal tl = new ThreadLocal();
public static void main (String[] args){
if (tl.get() == null) {
System.out.println("从未放过值");
tl.set("我的值");
}
System.out.println(tl.get());
System.out.println(tl.get());
}
}
运行结果为:

从结果来看,第一次调用tl对象的get()方法时返回的值为null,并且只有在调用set()方法之后才能检索该值.

如下: 每个线程在设置和获取时都是自己的个人价值
public class ThreadMain {
public static void main(String[] args) {
final ThreadLocal threadLocal = new ThreadLocal();
Thread thread1 = new Thread(new Runnable() {
@SuppressWarnings("all")
public void run() {
threadLocal.set("线程一得值");
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + "----" + threadLocal.get());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
thread1.setName("线程一");
thread1.start();
Thread thread2 = new Thread(new Runnable() {
@SuppressWarnings("all")
public void run() {
threadLocal.set("线程二得值");
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + "----" + threadLocal.get());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
thread2.setName("线程二");
thread2.start();
}
}
我们可以继承ThreadLocal并重写其initialValue()方法,例如:
public class MyThreadLocal extends ThreadLocal {
@Override
protected Object initialValue() {
return "我的初始值";
}
}

使用InheritableThreadLocal类让子线程从父线程获取值.
public class InheritableThreadLocalExt extends InheritableThreadLocal {
@Override
protected Object initialValue() {
return "InheritableThreadLocalExt";
}
}
public class ThreadMain {
static InheritableThreadLocalExt inheritableThreadLocalExt = new InheritableThreadLocalExt();
public static void main(String[] args) {
try {
for (int i = 0; i < 10; i++) {
System.out.println(" 在Main线程中取值="+inheritableThreadLocalExt.get());
Thread.sleep(100);
}
Thread.sleep(2000);
inheritableThreadLocalExt.set("first change");
ThreadA threadA = new ThreadA();
threadA.start();
Thread.sleep(300);
inheritableThreadLocalExt.set("second change");
Thread.sleep(2000);
System.out.println("last value = "+inheritableThreadLocalExt.get());
new ThreadA().start();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
static class ThreadA extends Thread {
@Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
System.out.println("在ThreadA线程中取值=" + inheritableThreadLocalExt.get());
Thread.sleep(100);
}
inheritableThreadLocalExt.set("change");
System.out.println("在ThreadA线程中取值=" + inheritableThreadLocalExt.get());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
结果:


要知道的结果是: 当子线程调用get()方法时多线程编程,如线程中InheritableThreadLocal的初始值是继承的初始值,则它将始终是父线程中InheritableThreadLocal的当前值.
修改上面的InheritableThreadLocalExt代码,并将方法childValue重写为:
public class InheritableThreadLocalExt extends InheritableThreadLocal {
@Override
protected Object initialValue() {
return "InheritableThreadLocalExt";
}
@Override
protected Object childValue(Object parentValue) {
return "child value";
}
}
其他恒定运算结果为:

从结果中可以看出: 重写childValue方法后,无论父线程中InheritableThreadLocal的值如何,子线程中InheritableThreadLocal的初始值都是childValue中返回的值.
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-279718-1.html
我就是我是颜色不一样的烟火
但使得定远镇压也因此丧失了再战能力
赔一件就行