背景:并发知识是一个程序员段位升级的体现,同样也是进入BAT的必经之路,有必要把并发知识重新梳理一遍。
并发concurrent:
使用ThreadLocal可以实现线程范围内共享变量,线程A写入的值和线程B获取到的结果一致;ReentrantReadWriteLock允许多个读线程或多个写线程同时进行,但不允许写线程和读线程同时进行;使用Callable可以得到线程执行的返回结果;Exchanger可以相互交换家线程执行的结果;这些使用方法大致都一样,JDk参考文档里面哪里不会点哪里,下面写个ThreadLocal实现线程范围内变量共享,里面还用到了一下饿汉模式:
执行结果如图中控制台打印,使用ThreadLocal保证了线程0和线程1读取到的值与写入的一致。
1 import java.util.Random; 2 import java.util.concurrent.locks.ReentrantReadWriteLock; 3 import lombok.Data; 4 5 public class ThreadLocalTest { 6 //ThreadLocal 实现线程范围内共享变量 7 private static ThreadLocal<Integer> x = new ThreadLocal<Integer>(); 8 private static ThreadLocal<MyThreadScopeData> myThreadScopeData = new ThreadLocal<MyThreadScopeData>(); 9 public static void main(String[] args) { 10 new ReentrantReadWriteLock(); 11 for(int i = 0; i<2; i++) { 12 new Thread(new Runnable() { 13 @Override 14 public void run() { 15 int data = new Random().nextInt(); 16 System.out.println(Thread.currentThread().getName() 17 +" has put data: "+ data); 18 x.set(data); // 存的时候与当前线程相关 取的时候也是与当前线程相关 19 //MyThreadScopeData.getInstance()拿到与本线程实例相关的对象: 不用反复new对象来getter/setter 20 MyThreadScopeData.getThreadInstance().setName("name: "+data); 21 MyThreadScopeData.getThreadInstance().setAge(data); 22 new A().get(); 23 new B().get(); 24 } 25 }).start(); 26 } 27 } 28 29 static class A{ 30 public void get() { 31 int data = x.get(); 32 System.out.println("A from "+Thread.currentThread().getName()+" get data: "+data); 33 //MyThreadScopeData.getInstance()拿到与本线程实例相关的对象 34 MyThreadScopeData myData = MyThreadScopeData.getThreadInstance(); 35 System.out.println("A from "+Thread.currentThread().getName() 36 +" getMyData: "+myData.getName() +","+myData.getAge()); 37 } 38 } 39 40 static class B{ 41 public void get() { 42 int data = x.get(); 43 System.out.println("B from "+Thread.currentThread().getName()+" get data: "+data); 44 //MyThreadScopeData.getInstance()拿到与本线程实例相关的对象 45 MyThreadScopeData myData = MyThreadScopeData.getThreadInstance(); 46 System.out.println("B from "+Thread.currentThread().getName() 47 +" getMyData: "+myData.getName() +","+myData.getAge()); 48 } 49 } 50 51 //设计自己线程范围内变量的共享,不需要创建对象,只需调用线程即可用到线程内的变量 52 @Data 53 static class MyThreadScopeData{ 54 //构造方法私有化,外部没发直接调用,但是可以调用里面的静态方法 55 private MyThreadScopeData() { } 56 public static /*synchronized*/ MyThreadScopeData getThreadInstance() { 57 MyThreadScopeData instance = map.get(); 58 if (instance == null) { 59 //饿汉模式 : 第一次来创建 60 instance = new MyThreadScopeData(); 61 map.set(instance); 62 } 63 return instance; 64 } 65 // private static MyThreadScopeData instance = null; // new MyThreadScopeData(); 66 private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<MyThreadScopeData>(); 67 private String name; 68 private int age; 69 } 70 71 }