Java 线程范围内的数据共享机制,需要解决的问题是 : 多个业务模块针对同一个static变量的操作 要保证在不同线程中 各模块操作的是自身对应的变量对象
实例 A B 两个类 需要操作同一个static变量 data
初步代码 可能如下:
执行结果:
分析结果可以看出 线程0 赋值数据 350455289,线程1 赋值数据 -1313940209,模块AB 拿到的data 却只是线程1 赋值的结果,这就说明在线程 0 赋值之后,AB操作之前,线程1 就已经将data的值修改为 -1313940209 了。
简单一点的修改 可以如下:
结果如下
将数据与当前线程相挂钩的话 那么显然是可以利用ThreadLocal这个类
ThreadLocal 就相当于一个 Map,key就是当前线程,value为当前线程对应的值, 那么改造上面的代码得到下面的代码:
代码执行完以后会得到同样的效果。
接下来还有一个问题 上面一直讨论的是线程间共享一个变量 那么如果是多个变量呢?
要直接ThreadLocal每次只能是一个变量和当前线程挂钩 如果有多个变量要和当前线程挂钩的话 就得生命多个ThreadLocal对象 这样子做很显然是不合理的。那如何处理呢?
由于ThreadLocal可以并且只能和一个变量挂钩,那么我们可以将这个变量设置为一个变量的容器,容器中可以存在多个变量,这也就是将需要和当前线程绑定的变量封装到一个实体类中
[size=medium]
ThreadLocal 是并发程序的一种解决方案,他利用空间换时间,也就是为每个线程分配空间来实现多线程,ThreadLocal 完全不使用锁,因此他不是一种数据共享的锁。
从性能上来说,ThreadLocal 并不具备绝对的优势,但是作为一种完全不使用锁的多线程解决方案,在高并发的情况下,在一定程度上可以减少锁的竞争。
[/size]
实例 A B 两个类 需要操作同一个static变量 data
初步代码 可能如下:
package threadLocal;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
/**
* 线程范围内的共享数据
* @author jingfn
*
*/
public class ThreadScopeShareDate {
private static int data ;
public static void main(String[] args) {
for(int i=0;i<2;i++)
new Thread(new Runnable(){
public void run(){
data = new Random().nextInt();
System.out.println(Thread.currentThread().getName()+"--put data "+data);
new A().get();
new B().get();
}
}).start();
}
static class A{
private void get(){
System.out.println("A--get data from "+Thread.currentThread().getName()+" of "+data);
}
}
static class B{
private void get(){
System.out.println("B--get data from "+Thread.currentThread().getName()+" of "+data);
}
}
}
执行结果:
Thread-0--put data 350455289
Thread-1--put data -1313940209
A--get data from Thread-0 of -1313940209
A--get data from Thread-1 of -1313940209
B--get data from Thread-1 of -1313940209
B--get data from Thread-0 of -1313940209
分析结果可以看出 线程0 赋值数据 350455289,线程1 赋值数据 -1313940209,模块AB 拿到的data 却只是线程1 赋值的结果,这就说明在线程 0 赋值之后,AB操作之前,线程1 就已经将data的值修改为 -1313940209 了。
简单一点的修改 可以如下:
package threadLocal;
import java.util.Random;
/**
* 线程范围内的共享数据
* @author jingfn
*
*/
public class ThreadScopeShareDate {
private static int data ;
public static void main(String[] args) {
for(int i=0;i<2;i++)
new Thread(new Runnable(){
public void run(){
synchronized(ThreadScopeShareDate.class){
data = new Random().nextInt();
System.out.println(Thread.currentThread().getName()+"--put data "+data);
new A().get();
new B().get();
}
}
}).start();
}
static class A{
private void get(){
System.out.println("A--get data from "+Thread.currentThread().getName()+" of "+data);
}
}
static class B{
private void get(){
System.out.println("B--get data from "+Thread.currentThread().getName()+" of "+data);
}
}
}
结果如下
Thread-0--put data -30716152
A--get data from Thread-0 of -30716152
B--get data from Thread-0 of -30716152
Thread-1--put data 913737008
A--get data from Thread-1 of 913737008
B--get data from Thread-1 of 913737008
将数据与当前线程相挂钩的话 那么显然是可以利用ThreadLocal这个类
ThreadLocal 就相当于一个 Map,key就是当前线程,value为当前线程对应的值, 那么改造上面的代码得到下面的代码:
package threadLocal;
import java.util.Random;
/**
* 线程范围内的共享数据
* @author jingfn
*
*/
public class ThreadScopeShareDate {
private static int data ;
private static ThreadLocal<Integer> localdata = new ThreadLocal<Integer>();
public static void main(String[] args) {
for(int i=0;i<2;i++)
new Thread(new Runnable(){
public void run(){
synchronized(ThreadScopeShareDate.class){
data = new Random().nextInt();
localdata.set(data);
System.out.println(Thread.currentThread().getName()+"--put data "+data);
new A().get();
new B().get();
}
}
}).start();
}
static class A{
private void get(){
System.out.println("A--get data from "+Thread.currentThread().getName()+" of "+localdata.get());
}
}
static class B{
private void get(){
System.out.println("B--get data from "+Thread.currentThread().getName()+" of "+localdata.get());
}
}
}
代码执行完以后会得到同样的效果。
接下来还有一个问题 上面一直讨论的是线程间共享一个变量 那么如果是多个变量呢?
要直接ThreadLocal每次只能是一个变量和当前线程挂钩 如果有多个变量要和当前线程挂钩的话 就得生命多个ThreadLocal对象 这样子做很显然是不合理的。那如何处理呢?
由于ThreadLocal可以并且只能和一个变量挂钩,那么我们可以将这个变量设置为一个变量的容器,容器中可以存在多个变量,这也就是将需要和当前线程绑定的变量封装到一个实体类中
package threadLocal;
import java.util.Random;
/**
* 线程范围内的共享数据
* @author jingfn
*
*/
public class ThreadScopeShareDateContainer {
private static int data ;
public static void main(String[] args) {
for(int i=0;i<2;i++)
new Thread(new Runnable(){
public void run(){
synchronized(ThreadScopeShareDateContainer.class){
data = new Random().nextInt();
Container.getInstance().setData1(data);
Container.getInstance().setData2(data);
System.out.println(Thread.currentThread().getName()+"--put data "+data);
new A().get();
new B().get();
}
}
}).start();
}
static class A{
private void get(){
System.out.println("A--get data from "+Thread.currentThread().getName()+" of "+Container.getInstance().getData1()+"--"+Container.getInstance().getData2());
}
}
static class B{
private void get(){
System.out.println("B--get data from "+Thread.currentThread().getName()+" of "+Container.getInstance().getData1()+"--"+Container.getInstance().getData2());
}
}
}
class Container{
private int data1,data2;
private static ThreadLocal<Container> local = new ThreadLocal<Container>();
public static Container getInstance(){
Container container = local.get();;
if(container == null){
container = new Container();
local.set(container);
}
return container;
}
public int getData1() {
return data1;
}
public void setData1(int data1) {
this.data1 = data1;
}
public int getData2() {
return data2;
}
public void setData2(int data2) {
this.data2 = data2;
}
}
[size=medium]
ThreadLocal 是并发程序的一种解决方案,他利用空间换时间,也就是为每个线程分配空间来实现多线程,ThreadLocal 完全不使用锁,因此他不是一种数据共享的锁。
从性能上来说,ThreadLocal 并不具备绝对的优势,但是作为一种完全不使用锁的多线程解决方案,在高并发的情况下,在一定程度上可以减少锁的竞争。
[/size]