1.线程范围内共享变量
1.1 前奏:
使用一个Map来实现线程范围内共享变量
public class ThreadScopeShareData { static Map<Thread, Integer> dataMap = 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() + " put data " + data); dataMap.put(Thread.currentThread(), data); new A().get(); new B().get(); } }).start(); } } static class A { public void get() { System.out.println(Thread.currentThread().getName() + " get data " + dataMap.get(Thread.currentThread())); } } static class B { public void get() { System.out.println(Thread.currentThread().getName() + "get data " + dataMap.get(Thread.currentThread())); } } }
1.2 ThreadLocal类实际上就是一种map
/** * ThreadLocal 类 这里ThreadLocal存放一个变量,如果有多个变量, 可以先将多个变量封装为一个对象 * * @author Administrator * */ public class ThreadLocalTest { static ThreadLocal<Integer> x = new ThreadLocal<>(); // 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() + " put data " + data); x.set(data); new A().get(); new B().get(); } }).start(); } } static class A { public void get() { System.out.println(Thread.currentThread().getName() + " get data " + x.get()); } } static class B { public void get() { System.out.println(Thread.currentThread().getName() + "get data " + x.get()); } } }
2.线程范围内共享多个变量,可以将多个变量封装为一个对象
/** * ThreadLocal 类 这里ThreadLocal存放一个变量,如果有多个变量, 可以先将多个变量封装为一个对象 * * @author Administrator * */ public class ThreadLocalTest { static ThreadLocal<Integer> x = new ThreadLocal<>(); // 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() + " put data " + data); x.set(data); MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();//获取与线程绑定的对象 myData.setName("name"+data); myData.setAge(data); System.out.println(Thread.currentThread().getName() + " put Object " + "name: "+myData.getName()+","+" age: "+myData.getAge()); new A().get(); new B().get(); } }).start(); } } static class A { public void get() { System.out.println(Thread.currentThread().getName() + " get data " + x.get()); MyThreadScopeData instance = MyThreadScopeData.getThreadInstance(); //直接获取与该线程相关的对象 System.out.println(Thread.currentThread().getName() + " get Object " + "name: "+instance.getName()+","+" age: "+instance.getAge()); } } static class B { public void get() { System.out.println(Thread.currentThread().getName() + "get data " + x.get()); MyThreadScopeData instance = MyThreadScopeData.getThreadInstance(); //直接获取与该线程相关的对象 System.out.println(Thread.currentThread().getName() + " get Object " + "name: "+instance.getName()+","+" age: "+instance.getAge()); } } } // 单例 class MyThreadScopeData { //类的实例是与线程相关的,那么类的设计就交由类自身完成,只要调用自然就是与线程有关的 private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<>(); private MyThreadScopeData() { } public static MyThreadScopeData getThreadInstance() { // 线程间是相互独立的,这里不需要考虑同步 MyThreadScopeData instance = map.get(); if (instance == null) { instance = new MyThreadScopeData(); map.set(instance); } return instance; } private String name; private Integer age; /** * @return the name */ public String getName() { return name; } /** * @param name * the name to set */ public void setName(String name) { this.name = name; } /** * @return the age */ public Integer getAge() { return age; } /** * @param age * the age to set */ public void setAge(Integer age) { this.age = age; } }
打印结果
Thread-1 put data -723086824
Thread-0 put data 772514756
Thread-1 put Object name: name-723086824, age: -723086824
Thread-0 put Object name: name772514756, age: 772514756
Thread-0 get data 772514756
Thread-1 get data -723086824
Thread-0 get Object name: name772514756, age: 772514756
Thread-1 get Object name: name-723086824, age: -723086824
Thread-0get data 772514756
Thread-1get data -723086824
Thread-0 get Object name: name772514756, age: 772514756
Thread-1 get Object name: name-723086824, age: -723086824
类的实例是与线程相关的,那么类的设计就交由类自身完成,只要调用自然就是与线程有关的 strust2的主要思想就是这么设计的
参看JAVA API
ThreadLocal有一个 remove()方法
可以移除与该线程相关的变量
remove()
Removes the current thread's value for this thread-local variable.
补充:
虚拟机的对应类 Runtime ,中有一个方法 addShutdownHook(Thread hook)
addShutdownHook(Thread hook)
Registers a new virtual-machine shutdown hook.
例如可以写一个发送邮件的线程Thread,当虚拟机挂掉之前会调用传入的Thread,发送一封邮件。
线程中是不是也应该有这种机制,当一个线程挂掉之前可以执行一个之前注册好的事件,或者有一个监听器在监听线程的状态,从而进行回调
在获取到线程挂掉的通知,就可以把该线程相关的变量全部remove获取clear掉
多个线程访问共享对象和数据的方式 (启用4个线程,其中2个线程对j加1,2个线程对j减1)
如果每个线程执行的代码相同,可以使用同一个Runnable对象,这个Runnable对象中有那个共享数据,例如卖票系统可以这个做。
第一种方式:将共享数据封装在另外一个对象中,然后将这个对象逐一传递给各个Runnable对象。每个线程对共享数据的操作方法也分配到那个对象身上去完成,这样容易实现针对该数据进行的各个操作的互斥和通信。
public class MutilThreadShareData { public static void main(String[] args) { final ShareData1 data1 = new ShareData1(); //两个线程操作同一个对象 for(int i = 0;i<2;i++){ new Thread(new Runnable1(data1)).start(); new Thread(new Runnable2(data1)).start(); } } static class Runnable1 implements Runnable{ private ShareData1 data1; public Runnable1(ShareData1 data1) { this.data1 = data1; } @Override public void run() { data1.increment(); } } static class Runnable2 implements Runnable{ private ShareData1 data1; public Runnable2(ShareData1 data1) { this.data1 = data1; } @Override public void run() { data1.decrement(); } } } class ShareData1{ private int j = 0; void increment(){ j++; System.out.println(j); } void decrement(){ j--; System.out.println(j); } }
第二种: 将这些Runnable对象作为某一个类中的内部类,共享数据作为这个外部类中的成员变量,每个线程对共享数据的操作方法也分配给外部类,以便实现对共享数据进行的各个操作的互斥和通信,作为内部类的各个Runnable对象调用外部类的这些方法。
public class MutilThreadShareData { private static ShareData1 data1 = new ShareData1(); //两个线程操作同一个对象 public static void main(String[] args) { for(int i = 0;i<2;i++){ new Thread(new Runnable() { @Override public void run() { data1.increment(); } }).start(); new Thread(new Runnable() { @Override public void run() { data1.decrement(); } }).start(); } } } class ShareData1{ private int j = 0; void increment(){ j++; System.out.println(j); } void decrement(){ j--; System.out.println(j); } }
第三种:
public class MutilThreadShareData { private static int j = 0; public static void main(String[] args) { for(int i = 0;i<2;i++){ new Thread(new Inc()).start(); new Thread(new Dec()).start(); } } static class Inc implements Runnable{ @Override public void run() { for(int i = 0;i<100;i++){ j++; System.out.println(j); } } } static class Dec implements Runnable{ @Override public void run() { for(int i = 0;i<100;i++){ j--; System.out.println(j); } } } }
一个外部类有两个内部类,两个内部类如何共享数据,都操作外部类的成员变量得到共享数据的目的