1.多线程范围内访问共享对象和数据的方式。
1).如果每个线程要执行的代码一样,可以使用同一个Runnable对象,这个Runnable对象中有共享数据,例如:买票系统。
2).每一个线程要执行的代码不一样,这样就需要使用多个Runnable对象了。有以下几种方式:
(1).将需要共享的数据单独封装在一个对象中,创建该对象的实例逐一传递给Runnable对象。
<span style="font-size:18px;"><span style="font-size:24px;"> final ShareData data =new ShareData();
new Thread(
new Runnable(){
@Override
public void run() {
while(true){
data.increment();
}
}}).start();
new Thread(
new Runnable(){
@Override
public void run() {
while(true){
data.decrement();
}
}}).start();
}
}
class ShareData{
private int j ;
public synchronized void increment(){
j++;
System.out.println(Thread.currentThread().getName()+ " increment "+j);
}
public synchronized void decrement(){
j--;
System.out.println(Thread.currentThread().getName()+ " decrement "+j);
}
}</span></span>
(2).将需要共享的数据封装在Runnable对象中。
<span style="font-size:18px;"><span style="font-size:24px;">class Runnable1 implements Runnable{
@Override
public void run() {
// ...
}
}
class Runnable2 implements Runnable
{
@Override
public void run() {
// ...
}
}</span></span>
(3).将Runnable对象作为某一个类的内部类, 共享数据作为这个类的外部类。
2).极端的一种方式,即在任意一个类中定义一个static变量,这将被所有线程共享。
2.线程范围内的共享数据。
对于同一份程序代码,多个模块在同一个线程中运行时要共享一份数据,而在另外一个线程运行时又共享另外一份数据。
自已来做的话,也很好做。
<span style="font-size:18px;"><span style="font-size:24px;">package com.hb;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class ThreadLocal {
private final static Map<Thread, Integer> threadData = new HashMap<Thread, Integer>();
public static void main(String[] args) {
// 创建三个线程,并且生产三个数据
for (int i = 0; i < 3; i++) {
new Thread(new Runnable() {
@Override
public void run() {
int data = new Random().nextInt();
threadData.put(Thread.currentThread(), data);
System.out.println(Thread.currentThread().getName()
+ " has put data " + data);
new A().get();
new B().get();
}
}).start();
}
}
// 模块A
static class A {
int data = threadData.get(Thread.currentThread());
public void get() {
System.out.println("A from " + Thread.currentThread().getName()
+ " get data " + data);
}
}
// 模块B
static class B {
int data = threadData.get(Thread.currentThread());
public void get() {
System.out.println("B from " + Thread.currentThread().getName()
+ " get data " + data);
}
}
}
</span></span>
java对这个threadData进行了封装,ThreadLocal相当于一个Map,每一个线程调用全局ThreadLocal对象的set方法,就相当于往其内部的map增加一条记录。key分别是各自的线程。
<span style="font-size:18px;">package com.hb;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class ThreadLocalTest {
// private final static Map<Thread, Integer> threadData = new HashMap<Thread, Integer>();
private final static ThreadLocal<Integer> threadData=new ThreadLocal();
public static void main(String[] args) {
// 创建三个线程,并且生产三个数据
for (int i = 0; i < 3; i++) {
new Thread(new Runnable() {
@Override
public void run() {
int data = new Random().nextInt();
// threadData.put(Thread.currentThread(), data);
threadData.set(data);
System.out.println(Thread.currentThread().getName()
+ " has put data " + data);
new A().get();
new B().get();
}
}).start();
}
}
// 模块A
static class A {
int data = threadData.get();//threadData.get(Thread.currentThread());
public void get() {
System.out.println("A from " + Thread.currentThread().getName()
+ " get data " + data);
}
}
// 模块B
static class B {
int data = threadData.get();//threadData.get(Thread.currentThread());
public void get() {
System.out.println("B from " + Thread.currentThread().getName()
+ " get data " + data);
}
}
}
</span>
值得注意的是一个ThreadLocal代表一个变量,故其中只能放一个数据。那我想放多个怎么办?打包呗。
l实现对ThreadLocal变量的封装,让外界不要直接操作ThreadLocal变量。
对基本类型的数据的封装,这种应用相对很少见。
对对象类型的数据的封装,比较常见,即让某个类针对不同线程分别创建一个独立的实例对象。
<span style="font-size:18px;">package com.hb;
import java.util.Random;
import com.hb.ThreadLocalTest.A;
import com.hb.ThreadLocalTest.B;
public class ThreadLocalTest2 {
public static void main(String[] args) {
// 创建三个线程,并且生产三个数据
for (int i = 0; i < 3; i++) {
new Thread(new Runnable() {
@Override
public void run() {
int data = new Random().nextInt();
MyThreadScopeData.getThreadInstance().setName("name"+data);
MyThreadScopeData.getThreadInstance().setAge(data);
System.out.println(Thread.currentThread().getName()
+ " has put data " + data);
new A().get();
new B().get();
}
}).start();
}
}
static class A{
public void get(){
MyThreadScopeData myData =MyThreadScopeData.getThreadInstance();
System.out.println("A from "+Thread.currentThread().getName()
+ " get name "+myData.getName()+", get age "+myData.getAge());
}
}
static class B{
public void get(){
MyThreadScopeData myData =MyThreadScopeData.getThreadInstance();
System.out.println("B from "+Thread.currentThread().getName()
+ " get name "+myData.getName()+", get age "+myData.getAge());
}
}
}
class MyThreadScopeData{
//将ThreadLocal封装在此。
private MyThreadScopeData(){}
private static ThreadLocal<MyThreadScopeData> maps=new ThreadLocal<MyThreadScopeData>();
public static MyThreadScopeData getThreadInstance(){
MyThreadScopeData instance =maps.get();
if(instance == null){
instance =new MyThreadScopeData();
maps.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;
}
}
</span>