线程范围的共享数据包括线程范围内共享和线程间共享数据
- 线程范围内共享数据
线程范围内共享数据有两种方式:自定义一个Map<Thread, Object>用来保存线程的数据或者是用ThreadLocal类。
使用Map<Thread, Object>
package traditional;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class ThreadScopeShareData {
private static Map<Thread,Integer> threadMap = new HashMap<Thread,Integer>();
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);
threadMap.put(Thread.currentThread(), data);
new A().get();
new B().get();
}
}).start();
}
}
static class A{
public void get(){
int data = threadMap.get(Thread.currentThread());
System.out.println("A from "+ Thread.currentThread().getName()+
"has put data : "+ data);
}
}
static class B{
public void get(){
int data = threadMap.get(Thread.currentThread());
System.out.println("B from "+ Thread.currentThread().getName()+
"has put data : "+ data);
}
}
}
使用ThreadLocal类
package traditional;
import java.util.Random;
/**
* ThreadLocal实现线程范围的共享变量
*/
public class ThreadLocalTest {
private static ThreadLocal<Integer> threadLocal = 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.set(data);// 把data数据存储到当前线程
/*
* 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() {
int data = threadLocal.get();// 取到当前线程的data值
System.out.println("A from " + Thread.currentThread().getName() + " has put data : " + data);
MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();
System.out.println("A from " + Thread.currentThread().getName() + " get myData : " + myData.getName() + ", "
+ myData.getAge());
}
}
static class B {
public void get() {
int data = threadLocal.get();// 取到当前线程的data值
System.out.println("B from " + Thread.currentThread().getName() + " has put data : " + data);
MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();
System.out.println("B from " + Thread.currentThread().getName() + " get myData : " + myData.getName() + ", "
+ myData.getAge());
}
}
}
/**
* 把ThreadLocal放到封装的类中
*
* 专门与线程绑定 在线程的任何地方调用该类的instance,就会产生与当前线程有关的实例
*
*/
class MyThreadScopeData {
// 类似于单例设计模式
private MyThreadScopeData() {
}
public /* synchronized */ static MyThreadScopeData getThreadInstance() {
MyThreadScopeData instance = map.get();
if (instance == null) {
instance = new MyThreadScopeData();
map.set(instance);
}
return instance;
}
// private static MyThreadScopeData instance = null;
private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<MyThreadScopeData>();
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;
}
}
- 线程之间共享数据
1、如果每个线程执行的代码相同,可以使用同一个Runnable对象,这个Runnable对象中有那个共享数据,例如买票系统就可以这么做。
2、如果每个线程执行的代码不相同,这时候就需要用不同的Runnable对象
2.1、把共享变量封装在一个对象中,然后把这个对象逐一传递给各个Runnable对象。(可以写自己的Runnable,然后以构造函数的方式传递共享变量进去)
// 设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1。写出程序。
package traditional;
public class MultiThreadShareData {
public static void main(String[] args) {
final ShareData1 data1 = new ShareData1();
new Thread(new Runnable(){
@Override
public void run() {
data1.decrement();
}
}).start();
new Thread(new Runnable(){
@Override
public void run() {
data1.increment();
}
}).start();
}
}
class ShareData1{
private int j = 0;
public synchronized void increment(){
j++;
}
public synchronized void decrement(){
j--;
}
}
内部类可以访问外部类的成员变量
另外的方法:
package traditional;
public class ThreadTest1 {
private int j;
public static void main(String args[]) {
ThreadTest1 tt = new ThreadTest1();
Inc inc = tt.new Inc();
Dec dec = tt.new Dec();
for (int i = 0; i < 2; i++) {
Thread t = new Thread(inc);
t.start();
t = new Thread(dec);
t.start();
}
}
private synchronized void inc() {
j++;
System.out.println(Thread.currentThread().getName() + "-inc:" + j);
}
private synchronized void dec() {
j--;
System.out.println(Thread.currentThread().getName() + "-dec:" + j);
}
class Inc implements Runnable {
public void run() {
for (int i = 0; i < 100; i++) {
inc();
}
}
}
class Dec implements Runnable {
public void run() {
for (int i = 0; i < 100; i++) {
dec();
}
}
}