1.互斥技术
- synchronized
- Lock
- Atomic
性能比较Atomic > Lock > synchronized,当然这不是绝对的。当线程数比较少时,synchronized的效率还是很可观的,并且用这个关键修饰的代码块阅读性很强。所以我们在编程时首先考虑到使用synchronized,当对并发的性能要求高的时候,才考虑使用Lock或者Atomic。Atomic适合简答的对象,如果对象多于复杂,不建议使用。
2.免锁容器
- CopyOnWriteArrayList
- CopyOnWriteArraySet
- concurrentHashMap
- ConcurrentLinkedQueue
在介绍勉锁容器时,先了解一下cow(copy on write)技术。该技术使用的对象一般是类似于数组这样存储量比较大的数据格式。在使用cow技术对数组进行写操作的时候,首先会对原始数组进行建立一个副本,然后对这个副本进行写操作。等到写操作完成后,通过一个原子操作将引用指向这个修改后的副本。这个写操作时互斥的,所以在某一时间段内只有一个线程对数组进行写操作。
在容器中引入cow技术后就是所谓的免锁容器,如CopyOnWriteArrayList。在免锁容器中,对数据的读和写操作可以同时发生,减少了获取锁和释放锁的操作。不过有一点需要注意,读到的始终是原数据的值。
免锁容器一般使用的场景是数据量比较少,读次数多,写次数少。
3.ReadWriteLock
该锁是针对写操作少,读操作多的情况使用。多个读者进行读操作时,不会产生冲突。当读锁被持有时,写操作不能进行。当写锁被其它任务持有时,任何读者都不能进行读操作,直到写锁被释放。
1 package com.dy.xidian; 2 3 import java.util.ArrayList; 4 import java.util.Collections; 5 import java.util.Random; 6 import java.util.concurrent.ExecutorService; 7 import java.util.concurrent.Executors; 8 import java.util.concurrent.TimeUnit; 9 import java.util.concurrent.locks.Lock; 10 import java.util.concurrent.locks.ReentrantReadWriteLock; 11 12 public class ReaderWriterList<T> { 13 private ArrayList<T> lockedList; 14 private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true); 15 public ReaderWriterList(int size, T initialValue) { 16 lockedList = new ArrayList<T>(Collections.nCopies(size, initialValue)); 17 } 18 19 public T set(int index, T element) { 20 Lock wlock = lock.writeLock(); 21 wlock.lock(); 22 try { 23 return lockedList.set(index, element); 24 } finally { 25 wlock.unlock(); 26 } 27 } 28 29 public T get(int index) { 30 Lock rlock = lock.readLock(); 31 rlock.lock(); 32 try { 33 if (lock.getReadLockCount() > 1) 34 System.out.println(lock.getReadLockCount()); 35 return lockedList.get(index); 36 } finally { 37 lock.readLock().unlock(); 38 } 39 } 40 41 public static void main(String[] args) { 42 new ReaderWriterListTest(30, 1); 43 } 44 } 45 46 class ReaderWriterListTest { 47 ExecutorService exec = Executors.newCachedThreadPool(); 48 private final static int SIZE = 100; 49 private static Random rand = new Random(47); 50 private ReaderWriterList<Integer> list = new ReaderWriterList<Integer>( 51 SIZE, 0); 52 53 private class Writer implements Runnable { 54 55 @Override 56 public void run() { 57 try { 58 for (int i = 0; i < 20; i++) { 59 list.set(i, rand.nextInt()); 60 TimeUnit.MILLISECONDS.sleep(100); 61 } 62 } catch (InterruptedException e) { 63 System.out.println("interrupted!"); 64 } 65 System.out.println("Writer finished, shutting down"); 66 } 67 } 68 69 private class Reader implements Runnable { 70 71 @Override 72 public void run() { 73 try { 74 while (!Thread.interrupted()) { 75 for (int i = 0; i < SIZE; i++) { 76 list.get(i); 77 TimeUnit.MILLISECONDS.sleep(1); 78 } 79 } 80 } catch (InterruptedException e) { 81 System.out.println("Read interrupted"); 82 } 83 } 84 } 85 86 public ReaderWriterListTest(int readers, int writers) { 87 for (int i = 0; i < readers; i++) 88 exec.execute(new Reader()); 89 for (int i = 0; i < writers; i++) 90 exec.execute(new Writer()); 91 } 92 }