并发编程-进阶
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了并发编程-进阶,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含9936字,纯文字阅读大概需要15分钟。
内容图文
volatile关键字
?强制线程到共享内存中读取数据,而不是从线程的工作空间的读取数据,从而可以可以使变量在多线程间可见 volatile无法保证原子性,volatile属于轻量级的同步性能比synchronized强很多(不加锁),但只能保证变脸在线程间的可见性,不能代替synzhronized的同步功能,netty框架大量使用了volatile关键字static是保证唯一性,不保证一致性,多个实例共享一个变量 比如: private static int a; 也就是说如果多个对象实例共享一个a属性,当一个对象实例改变了a属性值其他实例也就改变了 volatile保证一致性,不保证唯一性,多个实例多个volatile变量 比如: private volatile int a; 当多个类对象实例每个对象中a是不一样的,当其中一个改变其他的是不会改变的,volatile的唯一性是在并发线程是多个线程间使用一个对象的a变量的一致性 不能保证原子性是比如用volatile修饰的变量在自增的操作中i++中分三步,第一步读取i值,第二部赋值,第三部放回内存
- volatile与static关键字的区别
? ?
- 比如有一个i值为10在自增操作
- 有线程A与线程B两个线程
- 在线程A执行i++语句时会想从内存中获取i的值,就在这时线程B也执行i++语句,B也从内存中获取值,
- 然后线程A执行执行++操作,B也执行++操作,同时返回内存中是,其实只是+1
1 public class ThreadDemo09 implements Runnable { 2 3 private static volatile int sum = 0; 4 5 public static void add() { 6 System.out.println(Thread.currentThread().getName() + "循环前sum值" + sum); 7 for (int i = 0; i < 10000; i++) { 8 sum++; 9 } 10 System.out.println(Thread.currentThread().getName() + "循环后sum值" + sum); 11 } 12 13 @Override 14 public void run() { 15 add(); 16 } 17 18 public static void main(String[] args) { 19 ExecutorService es = Executors.newFixedThreadPool(10); 20 for (int i = 0; i < 10; i++) { 21 es.submit(new ThreadDemo09()); 22 } 23 es.shutdown(); 24 while (true) { 25 if (es.isTerminated()) { // 判断线程是否消亡 26 if (sum == 100000) { 27 System.out.println(sum + "=ok"); 28 } else { 29 System.out.println(sum + "=no"); 30 } 31 break; 32 } 33 } 34 } 35 }
? ?
atomicl类的原子性
? ?使用AtomicInteger等原子类可以保证变量的原子性,但是不能保证成员方法的原子性Atomic类采用CAS这种非锁机制?
1 private static AtomicInteger sum = new AtomicInteger(0); 2 3 public static void add() { 4 sum.addAndGet(1); 5 try { 6 Thread.sleep(1000); 7 } catch (InterruptedException e) { 8 e.printStackTrace(); 9 } 10 sum.addAndGet(9); 11 System.out.println(Thread.currentThread().getName() + "---> sum=" + sum); 12 } 13 14 public static void main(String[] args) { 15 ExecutorService es = Executors.newFixedThreadPool(10); 16 for (int i = 0; i < 10; i++) { 17 es.submit(new ThreadDemo10()); 18 } 19 es.shutdown(); 20 } 21 22 @Override 23 public void run() { 24 add(); 25 }
threadlocal
? ?使用ThreadLocal维护变量时,ThreadLocal给每个使用该变量的线程一个变量副本,所以每一个线程都可以独立修改变量内容,但是不会影响其他线程使用该变量?
final static ThreadLocal<Integer> local = new ThreadLocal<Integer>(); public static void main(String[] args) throws InterruptedException { new Thread(() -> { local.set(100); System.out.println(Thread.currentThread().getName() + " localSet=" + local.get()); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " localGet=" + local.get()); }, "t1").start(); Thread.sleep(1000); new Thread(() -> { Integer integer = local.get(); System.out.println(Thread.currentThread().getName() + " localSet=" + integer); local.set(200); System.out.println(Thread.currentThread().getName() + " localGet=" + local.get()); }, "t2").start(); }
? ?
同步类容器(古老的)
?Vector,HashTable都是古老的并发容器,都是使用Collections.synchronizedXXX()工厂方法创建的,并发状态下只能有一个线程访问对象,性能极低, collections可以将不是线程安全的集合变为线程安全的,就是在collections工具类中有每个集合的静态同步类,比如list,在collection有一个synchronizedList的静态内部类,该类实现了list接口同时继承synchronizedCollections类在这个,但是本质上还是使用的list的方法,只是在方法外包裹了一层synchronized锁?
public static void main(String[] args) { // final List<String> list = new ArrayList<>(); List<String> list = Collections.synchronizedList(new ArrayList<String>()); ExecutorService es = Executors.newFixedThreadPool(100); for (int i = 0; i < 10000; i++) { es.execute(()->{ list.add("5"); }); } es.shutdown(); while(true) { if(es.isTerminated()) { if(list.size() >= 10000) { System.out.println("线程安全"); }else { System.out.println("线程不安全"); } System.out.println(list.size()); break; } } }
并发类容器(新)
? ?JDK5.0以后有很多并发类比如concurrentMap属于并发类容器,vector与hashtable属于同步类容器,是将整个容器加锁,而concurrentMap是将需要操作的一个区域加锁,这样性能就大大的提高了 ConcurrentHashMap代替HashMap,HashTable ConcurrentSkipListMap 代替了 TreeMap ConcurrentHashMap将hash表分为16个segment(段),每个segment单独进行锁控制,从而减小了锁的粒度,提升了性能 ConcurrentHashMap ConcurrentHashMap替换了 HashMap 与 HashTable HashMap是线程不安全的,性能高. HashTable是线程安全的,性能低 ConcurrentHashMap 线程安全,性能比HashTable高 性能比较 HashMap > ConcurrentHashMap > HashTable
public static void TestMap() { /** * HashTable是同步类容器,ConcurrentHashMap并发类容器 同步类容器将整个容器加锁,性能低, * 并发类容器是将操作那个位置,给那个位置加锁. */ // 性能最高,不安全 // HashMap<String,Integer> map = new HashMap<String, Integer>(); // 在安全的情况下,性能高 ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<String, Integer>(); // 线程安全性能低 // Hashtable<String, Integer> map = new Hashtable<String, Integer>(); for (int i = 0; i < 10; i++) { new Thread(() -> { long start = System.currentTimeMillis(); for (int j = 0; j < 1000000; j++) { map.put(("a" + j), j); } long end = System.currentTimeMillis(); System.out.println(Thread.currentThread().getName() + "---------)" + (end - start)); }, "T" + i).start(); } }
ConcurrentHashMap新方法
?public static void TestMap1() { ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<String, Integer>(); map.put("a", 1); map.put("b", 1); map.put("c", 1); //key存在则替换 map.put("a", 2); //key存在则不替换 map.putIfAbsent("b", 2);//putIfAbsent方法存在不替换,但是 System.out.println(map.toString()); }
ConcurrentSkipListMap'
ConcurrentSkipListMap替换与storedMap对比
public static void TestMap1() { //性能低,线程安全 // SortedMap<String, Integer> map = Collections.synchronizedSortedMap(new TreeMap<String, Integer>()); //线程安全,性能高 ConcurrentSkipListMap<String,Integer> map = new ConcurrentSkipListMap<String,Integer>(); //线程不安全,性能高 // final SortedMap<String, Integer> map = new TreeMap<String, Integer>(); for (int i = 0; i < 10; i++) { new Thread(() -> { long start = System.currentTimeMillis(); for (int j = 0; j < 100000; j++) { map.put("a" + j, j); } long end = System.currentTimeMillis(); System.out.println(Thread.currentThread().getName() + "--->" + (end - start)); }, "T" + i).start(); } }
?
ConcurrentSkipListMaP新方法
?public static void TestSkipListMap1() { ConcurrentSkipListMap<String,Integer> map = new ConcurrentSkipListMap<String,Integer>(); map.put("a", 1); map.put("b1", 1); map.put("c", 1); //key存在则替换 map.put("a", 2); //key存在则不替换 map.putIfAbsent("b", 2); //并进行了排序 System.out.println(map.toString()); }
COW并发类容器
Copry on Write 容纳简称COW; 写时复制容器,向容器中添加元素时,先将容器进行Copy出一个新容器,然后将元素添加到新容器中,再将原容器中的引用指向新容器,并发读的时候不需要锁定容器,因为原容器没有变化,使用读写分离的思想,由于每次更新数据都会创建一个新容器,所以数据量较大并且频繁更新则对内存消耗很高,建议在高并发读的场景下使用 CopyOnWriteArraySet是基于CopyOnWriteArrayLiet实现的,其唯一的不同是add时调用的时候,CopyOnWriterArrayList的addIfAbsent方法同样采用锁保护,并创建一个新的大小+1的Object数组,遍历当前数组,如果Object中有当前元素,直接返回不添加,如果没有这个元素就添加到末尾,并返回,但CopyOnWriteArraySet 需要每次add都需要循环遍历,所以效率没有CopyOnWriteArrayList高?
- CopyOnWriteArrayList测试代码
public static void TestCOWArray() { CopyOnWriteArrayList<String> cowArray = new CopyOnWriteArrayList<String>(); cowArray.add("1"); cowArray.add("2"); cowArray.add("3"); cowArray.add("4"); cowArray.add("4"); // 假如存在则不添加,不存在添加 cowArray.addIfAbsent("2"); cowArray.addIfAbsent("5"); System.out.println(cowArray.toString()); } //源码 public boolean addIfAbsent(E e) { Object[] snapshot = getArray(); //获取当前数组 return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false : addIfAbsent(e, snapshot); } /** * A version of addIfAbsent using the strong hint that given * recent snapshot does not contain e. */ //添加一个数据需要查询数组是否有要添加的数据,有则不添加,没有则添加到末尾 private boolean addIfAbsent(E e, Object[] snapshot) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] current = getArray(); int len = current.length; if (snapshot != current) { // Optimize for lost race to another addXXX operation int common = Math.min(snapshot.length, len); for (int i = 0; i < common; i++) if (current[i] != snapshot[i] && eq(e, current[i])) return false; if (indexOf(e, current, common, len) >= 0) return false; } Object[] newElements = Arrays.copyOf(current, len + 1); newElements[len] = e; setArray(newElements); return true; } finally { lock.unlock(); } }
- CopyOnWriteArraySet测试代码
public static void TestCOWSet() { CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<String>(); set.add("1"); set.add("2"); set.add("3"); set.add("4"); System.out.println(set); set.add("4"); // 假如存在则不添加,不存在添加 set.add("5"); System.out.println(set); } //CopyOnWriteArraySet源码 //CopyOnWriteArraySet 中使用的就是CopyOnWriteArrayList public class CopyOnWriteArraySet<E> extends AbstractSet<E> implements java.io.Serializable { private static final long serialVersionUID = 5457747651344034263L; private final CopyOnWriteArrayList<E> al; //add方法时用的al的addIfAbsent方法每次添加都需要遍历 public boolean add(E e) { return al.addIfAbsent(e); }
内容总结
以上是互联网集市为您收集整理的并发编程-进阶全部内容,希望文章能够帮你解决并发编程-进阶所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。