黑马程序员-线程范围内数据共享
实现线程范围内数据共享,但不是全部线程都用相同的数据,而是每个线程有自己的数据,而该线程下是使用的该线程的数据
两种实现方式:
1,自定义集合
2,线程共享集合
3,线程共享集合优化
1,自定义集合
1 import java.util.HashMap; 2 import java.util.Map; 3 import java.util.Random; 4 5 public class ThreadScopeShareData { 6 7 //定义一个MAP集合,用与一对一的存放该线程和该线程的共享数据 8 private static Map<Thread, Integer> map = new HashMap<Thread, Integer>(); 9 public static void main(String[] args) { 10 11 //循环两次,创建两个线程 12 for (int i = 0; i < 2; i++) { 13 //创建一个匿名线程并一个匿名的Runnable实现类 14 new Thread(new Runnable() { 15 16 //实现run方法 17 @Override 18 public void run() { 19 //每一次进来产生一个随机数 20 int data = new Random().nextInt(); 21 //获得当前线程 22 Thread thr = Thread.currentThread(); 23 //把当前线程和随机数存入集合 24 map.put(thr, data); 25 26 System.out.println(thr.getName() + " run " + data); 27 28 //调用方法 29 new A().get(); 30 new B().get(); 31 32 } 33 }).start(); 34 } 35 } 36 37 static class A { 38 public void get() { 39 //通过调用本方法的线程获得共享数据 40 int data = map.get(Thread.currentThread()); 41 System.out.println(Thread.currentThread().getName() + " A " + data); 42 } 43 } 44 45 static class B { 46 public void get() { 47 //通过调用本方法的线程获得共享数据 48 int data = map.get(Thread.currentThread()); 49 System.out.println(Thread.currentThread().getName() + " B " + data); 50 } 51 } 52 53 }
控制台输出:
Thread-0 run 1304853885
Thread-1 run -212565129
Thread-0 A 1304853885
Thread-1 A -212565129
Thread-0 B 1304853885
Thread-1 B -212565129
2,系统的提供的线程共享集合
1 public class ThreadLocalDemo { 2 3 //定义线程共享集合 4 private static ThreadLocal<Integer> tl = new ThreadLocal<Integer>(); 5 private static ThreadLocal<MyThreadScopeData> myThreadScopeData = new ThreadLocal<MyThreadScopeData>(); 6 7 public static void main(String[] args) { 8 // TODO Auto-generated method stub 9 for (int i = 0; i < 2; i++) { 10 //创建一个匿名线程并一个匿名的Runnable实现类 11 new Thread(new Runnable() { 12 13 @Override 14 public void run() { 15 //获得随机数 16 int data = new Random().nextInt(); 17 //获得当前线程 18 Thread thr = Thread.currentThread(); 19 //把随机数存入线程共享集合 20 //注意:这里tl.set(data); 可以理解为tl.put(Thread.currentTherad(),data); 21 //这个集合会自动把存入的数据跟当前线程键值对应存储起来,当前线程为key,value为data 22 tl.set(data); 23 //把产生的对象存入集合 24 myThreadScopeData.set(new MyThreadScopeData("zhangsan", data)); 25 26 System.out.println(thr.getName() + " run " + data); 27 28 //调用方法 29 new A().get(); 30 new B().get(); 31 32 } 33 }).start(); 34 } 35 } 36 37 static class A { 38 public void get() { 39 //根据集合获取数据 40 //这里可以理解为:tl.get(Thread.currentThread()); 41 int data = tl.get(); 42 //根据集合获取对象 43 MyThreadScopeData mtsd = myThreadScopeData.get(); 44 45 System.out.println(Thread.currentThread().getName() + " A " + data 46 + "......" + mtsd.getName() + " A " + mtsd.getAge()); 47 48 } 49 } 50 51 static class B { 52 public void get() { 53 //根据集合获取数据 54 //这里可以理解为:tl.get(Thread.currentThread()); 55 int data = tl.get(); 56 //根据集合获取对象 57 MyThreadScopeData mtsd = myThreadScopeData.get(); 58 59 System.out.println(Thread.currentThread().getName() + " B " + data 60 + "......" + mtsd.getName() + " B " + mtsd.getAge()); 61 } 62 } 63 //定义一个测试对象 64 static class MyThreadScopeData{ 65 private String name; 66 private int age; 67 public MyThreadScopeData(String name, int age) { 68 super(); 69 this.name = name; 70 this.age = age; 71 } 72 public String getName() { 73 return name; 74 } 75 public void setName(String name) { 76 this.name = name; 77 } 78 public int getAge() { 79 return age; 80 } 81 public void setAge(int age) { 82 this.age = age; 83 } 84 } 85 }
控制台输出:
Thread-0 run -194815996
Thread-1 run -1415978357
Thread-0 A -194815996......zhangsan A -194815996
Thread-1 A -1415978357......zhangsan A -1415978357
Thread-0 B -194815996......zhangsan B -194815996
Thread-1 B -1415978357......zhangsan B -1415978357
3,系统的提供的线程共享集合优化
1 public class ThreadLocalOptimizeDemo { 2 3 //定义线程共享集合 4 private static ThreadLocal<Integer> tl = new ThreadLocal<Integer>(); 5 private static ThreadLocal<MyThreadScopeData> myThreadScopeData = new ThreadLocal<MyThreadScopeData>(); 6 7 public static void main(String[] args) { 8 // TODO Auto-generated method stub 9 for (int i = 0; i < 2; i++) { 10 //创建一个匿名线程并一个匿名的Runnable实现类 11 new Thread(new Runnable() { 12 13 @Override 14 public void run() { 15 //获得随机数 16 int data = new Random().nextInt(); 17 //获得当前线程 18 Thread thr = Thread.currentThread(); 19 //把随机数存入线程共享集合 20 //注意:这里tl.set(data); 可以理解为tl.put(Thread.currentTherad(),data); 21 //这个集合会自动把存入的数据跟当前线程键值对应存储起来,当前线程为key,value为data 22 tl.set(data); 23 24 //直接获得当前线程的测试对象 25 MyThreadScopeData mtsd = MyThreadScopeData.getThreadInstance(); 26 //赋值 27 mtsd.setAge(data); 28 mtsd.setName("zhangsan"); 29 30 System.out.println(thr.getName() + " run " + data); 31 32 //调用方法 33 new A().get(); 34 new B().get(); 35 36 } 37 }).start(); 38 } 39 } 40 41 static class A { 42 public void get() { 43 //根据集合获取数据 44 //这里可以理解为:tl.get(Thread.currentThread()); 45 int data = tl.get(); 46 //根据集合获取对象 47 MyThreadScopeData mtsd = myThreadScopeData.get(); 48 49 System.out.println(Thread.currentThread().getName() + " A " + data 50 + "......" + mtsd.getName() + " A " + mtsd.getAge()); 51 } 52 } 53 54 static class B { 55 public void get() { 56 //根据集合获取数据 57 //这里可以理解为:tl.get(Thread.currentThread()); 58 int data = tl.get(); 59 //根据集合获取对象 60 MyThreadScopeData mtsd = myThreadScopeData.get(); 61 62 System.out.println(Thread.currentThread().getName() + " B " + data 63 + "......" + mtsd.getName() + " B " + mtsd.getAge()); 64 } 65 } 66 //定义一个测试对象 67 static class MyThreadScopeData{ 68 69 public static MyThreadScopeData getThreadInstance(){ 70 //获取当前的线程的测试对象。 71 //我觉得这里是最精妙的,获取当前线程的测试对象,充分的利用了ThreadLocal集合的特性, 72 //然后和懒汉式单例模式非常巧妙的结合,在其他地方完全不用考虑这个对象是否存在、或者是否是同一个对象之类的 73 //直接在相应的线程调用这个方法就能获得相应线程的测试对象 74 MyThreadScopeData mtsd = myThreadScopeData.get(); 75 //如果该对象为null,表示集合中没有该线程的测试对象 76 if(mtsd == null){ 77 //创建对象,并存入集合 78 mtsd = new MyThreadScopeData(); 79 myThreadScopeData.set(mtsd); 80 } 81 return mtsd; 82 } 83 84 private String name; 85 private int age; 86 private MyThreadScopeData() { 87 super(); 88 } 89 public String getName() { 90 return name; 91 } 92 public void setName(String name) { 93 this.name = name; 94 } 95 public int getAge() { 96 return age; 97 } 98 public void setAge(int age) { 99 this.age = age; 100 } 101 } 102 }
控制台输出:
Thread-0 run -740588757
Thread-1 run -1715552337
Thread-0 A -740588757......zhangsan A -740588757
Thread-1 A -1715552337......zhangsan A -1715552337
Thread-1 B -1715552337......zhangsan B -1715552337
Thread-0 B -740588757......zhangsan B -740588757
总结:
1,第一种方法虽然也能实现效果,但是系统提供了专门来操作的对象不用白不用,而且还简便些,还有就是系统提供的对象在该线程结束后会自动回收结束线程在集合中的相关对象,自己建的集合则不行,即使行也要自己动手。
2,第三种方法虽然看起来比第二种方法繁琐、复杂,代码也多了,但是懒汉式单例模式那一块却是十分的精妙,一旦把这个方法完成后在其他地方就完全不用考虑测试对象的问题了赋值的时候通过方法拿到对象就可以直接赋值,用的时候也直接通过集合拿到就用。