线程范围内的共享数据
1、未实现线程共享变量
package cn.itcast.heima2;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class ThreadScopeShareData {
private static int data = 0;
// private static Map<Thread, Integer> threadData = new HashMap<Thread, Integer>();
public static void main(String[] args) {
//共启动2个线程
for(int i=0;i<2;i++){
//启动一个线程
new Thread(new Runnable(){
@Override
public void run() {
data = new Random().nextInt();
System.out.println(Thread.currentThread().getName()
+ " has put data :" + data);
//以当前线程为key值放入到map中,当取值时根据各自的线程取各自的数据
// threadData.put(Thread.currentThread(), data);
new A().get();
new B().get();
}
}).start();
}
}
static class A{
public void get(){
// int data = threadData.get(Thread.currentThread());
System.out.println("A from " + Thread.currentThread().getName()
+ " get data :" + data);
}
}
static class B{
public void get(){
// int data = threadData.get(Thread.currentThread());
System.out.println("B from " + Thread.currentThread().getName()
+ " get data :" + data);
}
}
}
2、线程范围内共享变量实现方式:
Map实现方式:
package cn.itcast.thread;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class TraditionaScopeshareData {
private static int data=0;
private static Map<Thread,Integer> threadData=new HashMap<Thread,Integer>();
public static void main(String[] args) {
// TODO Auto-generated method stub
for(int i=0;i<2;i++){
new Thread(
new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
int data=new Random().nextInt();
System.out.println(Thread.currentThread().getName()+"has put data:"+data);
threadData.put(Thread.currentThread(),data);
new A().get();
new B().get();
}
}).start();
}}
static class A{
public void get()
{
int data =threadData.get(Thread.currentThread());
System.out.println("A from"+Thread.currentThread().getName()+"has put data:"+data);
}
}
static class B{
public void get()
{
int data =threadData.get(Thread.currentThread());
System.out.println("B from"+Thread.currentThread().getName()+"has put data:"+data);
}
}
}
实现结果
Thread-0has put data:-498492583
Thread-1has put data:381688615
A fromThread-0has put data:-498492583
B fromThread-0has put data:-498492583
A fromThread-1has put data:381688615
B fromThread-1has put data:381688615
ThreadLocals实现方式
package cn.itcast.thread;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class ThreadLocalTest {
private static ThreadLocal<Integer> x = new ThreadLocal<Integer>();
public static void main(String[] args) {
// TODO Auto-generated method stub
for(int i=0;i<2;i++){
new Thread(
new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
int data=new Random().nextInt();
System.out.println(Thread.currentThread().getName()+"has put data:"+data);
x.set(data);//数据存进了线程
new A().get();
new B().get();
}
}).start();
}}
static class A{
public void get()
{
int data = x.get();
System.out.println("A from"+Thread.currentThread().getName()+"has put data:"+data);
}
}
static class B{
public void get()
{
int data = x.get();
System.out.println("B from"+Thread.currentThread().getName()+"has put data:"+data);
}
}
}
结果
Thread-0has put data:-145623389
A fromThread-0has put data:-145623389
B fromThread-0has put data:-145623389
Thread-1has put data:433511551
A fromThread-1has put data:433511551
B fromThread-1has put data:433511551
存在的问题:一个ThreadLocal代表一个变量,故其中只能放一个数据,如果你有两个变量要线程范围内共享,则要定义两个ThreadLocal。
解决方法:
package cn.itcast.thread;
import java.util.Random;
public class ThreadLocalTest {
// 方式一
// private static ThreadLocal<Integer> x = new ThreadLocal<Integer>();
private static ThreadLocal<MyThreadScopeData> myThreadScopeData = new ThreadLocal<MyThreadScopeData>();
public static void main(String[] args) {
for(int i=0;i<2;i++){
new Thread(new Runnable(){
@Override
public void run() {
int data = new Random().nextInt();
System.out.println(Thread.currentThread().getName()
+ " has put data :" + data);
// 方式一 ThreadLocal
// x.set(data);
// 方式二 new对象方式,将多个属性放到对象中
// MyThreadScopeData myData = new MyThreadScopeData();
// myData.setName("name" + data);
// myData.setAge(data);
// myThreadScopeData.set(myData);
// 方式三 使用单例模式
MyThreadScopeData.getThreadInstance().setName("name" + data);
MyThreadScopeData.getThreadInstance().setAge(data);
new A().get();
new B().get();
}
}).start();
}
}
static class A{
public void get(){
// 方式一 ThreadLocal
// int data = x.get();
// System.out.println("A from " + Thread.currentThread().getName()
// + " get data :" + data);
// 方式二 new对象方式,将多个属性放到对象中
// MyThreadScopeData myData = myThreadScopeData.get();;
// System.out.println("A from " + Thread.currentThread().getName()
// + " getMyData: " + myData.getName() + "," +
// myData.getAge());
// 方式三 使用单例模式
MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();
System.out.println("A from " + Thread.currentThread().getName()
+ " getMyData: " + myData.getName() + "," +
myData.getAge());
}
}
static class B{
public void get(){
// int data = x.get();
// System.out.println("B from " + Thread.currentThread().getName()
// + " get data :" + data);
// MyThreadScopeData myData = myThreadScopeData.get();;
// System.out.println("B from " + Thread.currentThread().getName()
// + " getMyData: " + myData.getName() + "," +
// myData.getAge());
MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();
System.out.println("B from " + Thread.currentThread().getName()
+ " getMyData: " + myData.getName() + "," +
myData.getAge());
}
}
}
class MyThreadScopeData{
private MyThreadScopeData(){}
private static MyThreadScopeData instance = null;//new MyThreadScopeData();
private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<MyThreadScopeData>();
public static /*synchronized*/ MyThreadScopeData getThreadInstance(){
MyThreadScopeData instance = map.get();
if(instance == null){
instance = new MyThreadScopeData();
map.set(instance);
}
return instance;
}
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
结果
Thread-1 has put data :-1622741359
Thread-0 has put data :-648762367
A from Thread-1 getMyData: name-1622741359,-1622741359
A from Thread-0 getMyData: name-648762367,-648762367
B from Thread-0 getMyData: name-648762367,-648762367
B from Thread-1 getMyData: name-1622741359,-1622741359
synchronized和使用ThreadLocal均可以解决以上的问题,只是这是两种不同的方式,synchronized是依赖锁的机制一个执行完后另一个再执行。ThreadLocal会为每一个线程维护一个和该线程绑定的变量的副本,从而隔离了多个线程的数据,每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。
概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。
当然ThreadLocal并不能替代同步机制,两者面向的问题领域不同。同步机制是为了同步多个线程对相同资源的并发访问,是为了多个线程之间进行通信的有效方式;而ThreadLocal是隔离多个线程的数据共享,从根本上就不在多个线程之间共享资源(变量),这样当然不需要对多个线程进行同步了。