A concurrent program has multiple logical threads of control. These threads may or may not run in parallel.java
A parallel program may or may not have more than one logical thread of control.node
并发是问题域中的概念:程序须要设计成可以处理多个同时(几乎同时)发生的事件;而并行则是方法域中的概念:经过将问题中的多个部分并发执行,来加速解决问题.程序员
并发是同一时间**应对(dealing with)多件事件的处理能力;并行是同一时间动手作(doing)**多件事情的能力算法
能够同时处理多个问题,可是每次只作一件事,是并发.编程
我妻子是一位教师。与众多教师同样,她极其善于处理多个任务。她虽然每次只能作一件事,但能够并发地处理多个任务。好比,在听一位学生朗读的时候,她能够暂停学生的朗读,以维持课堂秩序,或者回答学生的问题。这是并发,但并不并行(由于仅有她一我的,某一时刻只能进行一件事)。 但若是还有一位助教,则她们中一位能够聆听朗读,而同时另外一位能够回答问题。这种方式既是并发,也是并行。 假设班级设计了本身的贺卡并要批量制做。一种方法是让每位学生制做五枚贺卡。这种方法是并行,而(从总体看)不是并发,由于这个过程总体来讲只有一个任务。缓存
并发和并行常常被混淆的一个缘由是,传统的“线程与锁”模型并无显式支持并行。若是要用线程与锁模型为多核进行开发,惟一的选择就是写一个并发的程序,让其并行地运行在多核上。安全
并发程序一般是不肯定的, 并行程序多是肯定的. 使用一门直接支持并行的编程语言能够写出并行程序,而不会引入不入不 肯定性.网络
终于来到了你们所默认的并行形式——多处理器。从程序员的角度来看,多处理器架构最明 显的分类特征是其内存模型(共享内存模型或分布式内存模型)。多线程
共享内存模型(经过内存通讯)架构
分布式内存模型( 经过网络通讯 )
class Counter { private int count = 0; public synchronized void increment() { ++count; } ➤ public int getCount() { return count; } }
class Philosopher extends Thread { private Chopstick left, right; private Random random; public Philosopher(Chopstick left, Chopstick right) { this.left = left; this.right = right; random = new Random(); } public void run() { try { while(true) { Thread.sleep(random.nextInt(1000)); // Think for a while synchronized(left) { // Grab left chopstick // synchronized(right) { // Grab right chopstick // 15 Thread.sleep(random.nextInt(1000)); // Eat for a while } } } } catch(InterruptedException e) {} } }
class Philosopher extends Thread { private Chopstick first, second; private Random random; private int thinkCount; public Philosopher(Chopstick left, Chopstick right) { if(left.getId() < right.getId()) { first = left; second = right; } else { first = right; second = left; } random = new Random(); } public void run() { try { while(true) { ++thinkCount; if (thinkCount % 10 == 0) System.out.println("Philosopher " + this + " has thought " + thinkCount + " times"); Thread.sleep(random.nextInt(1000)); // Think for a while synchronized(first) { // Grab first chopstick synchronized(second) { // Grab second chopstick Thread.sleep(random.nextInt(1000)); // Eat for a while } } } } catch(InterruptedException e) {} } }
程序解释:当全部人同时决定进餐的时候,ABCD左手分别拿起1234号筷子(对于他们小的编号的筷子仍是在左手),这和上面的程序没啥不一样,可是差异就在这个E,他左边的筷子是大编号,因此他左手拿的是1,然而1被A拿了,因此他就一只筷子都拿不到,因此D能够正常进餐,就不会死锁
局限:获取锁的代码写的比较集中的话,有利于维护这个全局顺序,可是对于规模比较大的程序,使用锁的地方比较零散,各处都遵照这个顺序就显得不太实际.
技巧:使用对象的散列值做为锁的全局顺序
优势:适用于全部java对象,不用为锁对象专门定义并维护一个顺序,
缺点:可是对象的散列值不能保证惟一性(虽然概率很小), 不是无可奈何不要使用
if(System.identityHashCode(left) < System.identityHashCode(right)) { first = left; second = right; } else { first = right; second = left; }
private synchronized void updateProgress(int n) { for (ProgressListener listener: listeners) // listeners是累的一个field listener.onProgress(n); }
private void updateProgress(int n) { ArrayList<ProgressListener> listenersCopy; synchronized(this) { listenersCopy = (ArrayList<ProgressListener>)listeners.clone(); } for (ProgressListener listener: listenersCopy) listener.onProgress(n); }
Lock lock = new ReentrantLock(); lock.lock(); try{ //使用共享资源 } finally { //使用finally确保锁释放 lock.unlock(); }
final ReentrantLock l1 = new ReentrantLock(); final ReentrantLock l2 = new ReentrantLock(); Thread t1 = new Thread() { public void run() { try { l1.lockInterruptibly(); Thread.sleep(1000); l2.lockInterruptibly(); } catch (InterruptedException e) { System.out.println("t1 interrupted"); } } };
class Philosopher extends Thread { private ReentrantLock leftChopstick, rightChopstick; private Random random; private int thinkCount; public Philosopher(ReentrantLock leftChopstick, ReentrantLock rightChopstick) { this.leftChopstick = leftChopstick; this.rightChopstick = rightChopstick; random = new Random(); } public void run() { try { while(true) { ++thinkCount; if (thinkCount % 10 == 0) System.out.println("Philosopher " + this + " has thought " + thinkCount + " times"); Thread.sleep(random.nextInt(1000)); // Think for a while leftChopstick.lock(); try { if (rightChopstick.tryLock(1000, TimeUnit.MILLISECONDS)) { // Got the right chopstick try { Thread.sleep(random.nextInt(1000)); // Eat for a while } finally { rightChopstick.unlock(); } } else { // Didn't get the right chopstick - give up and go back to thinking System.out.println("Philosopher " + this + " timed out"); } } finally { leftChopstick.unlock(); } } } catch(InterruptedException e) {} } }
交替锁能够只锁住链表的一部分,容许不涉及被锁部分的其余线程自由访问链表.插入新的链表节点时,须要将待插入位置两边的节点加锁.首先锁住链表的前两个节点,若是这两个节点之间不是待插入的位置,那么就解锁第一个,并锁住第三个,以此类推,知道找到待插入位置并插入新的节点,最后解锁两边的节点
这种交替型的加锁和解锁顺序没法用内置锁实现,使用ReentrantLock能够
class ConcurrentSortedList { private class Node { int value; Node prev; Node next; ReentrantLock lock = new ReentrantLock(); Node() {} Node(int value, Node prev, Node next) { this.value = value; this.prev = prev; this.next = next; } } private final Node head; private final Node tail; public ConcurrentSortedList() { head = new Node(); tail = new Node(); head.next = tail; tail.prev = head; } //insert方法是有序的 遍历列表直到找到第一个值小于等于新插入的值得节点,在这个位置插入 public void insert(int value) { Node current = head; current.lock.lock(); Node next = current.next; try { while (true) { next.lock.lock(); try { if (next == tail || next.value < value) { Node node = new Node(value, current, next); next.prev = node; current.next = node; //!!!这里return要在两个finally都执行完后才会执行啊!!!但只是finally里的.不过要是return换成exit(0)就直接退出了 return; } } finally { current.lock.unlock(); } current = next; next = current.next; } } finally { next.lock.unlock(); } } public int size() { Node current = tail; int count = 0; while (current.prev != head) { ReentrantLock lock = current.lock; lock.lock(); try { ++count; current = current.prev; } finally { lock.unlock(); } } return count; } public boolean isSorted() { Node current = head; while (current.next.next != tail) { current = current.next; if (current.value < current.next.value) return false; } return true; } } class LinkedList { public static void main(String[] args) throws InterruptedException { final ConcurrentSortedList list = new ConcurrentSortedList(); final Random random = new Random(); class TestThread extends Thread { public void run() { for (int i = 0; i < 10000; ++i) list.insert(random.nextInt()); } } class CountingThread extends Thread { public void run() { while (!interrupted()) { System.out.print("\r" + list.size()); System.out.flush(); } } } Thread t1 = new TestThread(); Thread t2 = new TestThread(); Thread t3 = new CountingThread(); //注意一下这里的用法 这里先join再interrupted的用法 t1.start(); t2.start(); t3.start(); t1.join(); t2.join(); t3.interrupt(); System.out.println("\r" + list.size()); if (list.size() != 20000) System.out.println("*** Wrong size!"); if (!list.isSorted()) System.out.println("*** Not sorted!"); } }
ReentrantLock lock = new ReentrantLock(); Condition condition = lock.newCondition(); lock.lock(); try { while (! « condition is true » ) { condition.await(); } //使用共享资源 } finally { lock.unlock(); }
class Philosopher extends Thread { private boolean eating; private Philosopher left; private Philosopher right; private ReentrantLock table; private Condition condition; private Random random; private int thinkCount; public Philosopher ( ReentrantLock table ) { eating = false; this.table = table; condition = table.newCondition(); random = new Random(); } public void setLeft ( Philosopher left ) { this.left = left; } public void setRight ( Philosopher right ) { this.right = right; } public void run () { try { while ( true ) { think(); eat(); } } catch ( InterruptedException e ) { } } private void think () throws InterruptedException { table.lock(); try { eating = false; left.condition.signal(); right.condition.signal(); } finally { table.unlock(); } ++thinkCount; if ( thinkCount % 10 == 0 ) { System.out.println( "Philosopher " + this + " has thought " + thinkCount + " times" ); } Thread.sleep( 1000 ); } private void eat () throws InterruptedException { table.lock(); try { while ( left.eating || right.eating ) { condition.await(); } eating = true; } finally { table.unlock(); } Thread.sleep( 1000 ); } }
//Downloader.java private CopyOnWriteArrayList<ProgressListener> listeners; public void addListener(ProgressListener listener) { listeners.add(listener); } public void removeListener(ProgressListener listener) { listeners.remove(listener); } private void updateProgress(int n) { for (ProgressListener listener: listeners) listener.onProgress(n); }
//生产者 将page加到队尾 class Parser implements Runnable { private BlockingQueue<Page> queue; public Parser(BlockingQueue<Page> queue) { this.queue = queue; } public void run() { try { Iterable<Page> pages = new Pages(100000, "enwiki.xml"); for (Page page: pages) queue.put(page); } catch (Exception e) { e.printStackTrace(); } } } //消费者 class Counter implements Runnable { private BlockingQueue<Page> queue; private Map<String, Integer> counts; public Counter(BlockingQueue<Page> queue, Map<String, Integer> counts) { this.queue = queue; this.counts = counts; } public void run() { try { while(true) { Page page = queue.take(); if (page.isPoisonPill()) break; Iterable<String> words = new Words(page.getText()); for (String word: words) countWord(word); } } catch (Exception e) { e.printStackTrace(); } } private void countWord(String word) { Integer currentCount = counts.get(word); if (currentCount == null) counts.put(word, 1); else counts.put(word, currentCount + 1); } }
public static void main(String[] args) throws Exception { ArrayBlockingQueue<Page> queue = new ArrayBlockingQueue<Page>(100); HashMap<String, Integer> counts = new HashMap<String, Integer>(); Thread counter = new Thread(new Counter(queue, counts)); Thread parser = new Thread(new Parser(queue)); long start = System.currentTimeMillis(); counter.start(); parser.start(); parser.join(); queue.put(new PoisonPill()); counter.join(); long end = System.currentTimeMillis(); System.out.println("Elapsed time: " + (end - start) + "ms"); }
private void countWord(String word) { lock.lock(); try { Integer currentCount = counts.get(word); if (currentCount == null) counts.put(word, 1); else counts.put(word, currentCount + 1); } finally { lock.unlock(); } }
ExecutorService executor = Executors.newCachedThreadPool(); for (int i = 0; i < NUM_COUNTERS; ++i) executor.execute(new Counter(queue, counts)); Thread parser = new Thread(new Parser(queue)); parser.start(); parser.join(); for (int i = 0; i < NUM_COUNTERS; ++i) queue.put(new PoisonPill()); executor.shutdown();
//改用 ConcurrentHashMap private void countWord(String word) { while (true) { //理解一下这里的循环 若是下面的操做没有成功的话,就重试 Integer currentCount = counts.get(word); if (currentCount == null) { if (counts.putIfAbsent(word, 1) == null) //若是没有与1关联 则关联,有原子性 break; } else if (counts.replace(word, currentCount, currentCount + 1)) { break; } }
class Counter implements Runnable { private BlockingQueue<Page> queue; private ConcurrentMap<String, Integer> counts; private HashMap<String, Integer> localCounts; public Counter(BlockingQueue<Page> queue, ConcurrentMap<String, Integer> counts) { this.queue = queue; this.counts = counts; localCounts = new HashMap<String, Integer>(); } public void run() { try { while(true) { Page page = queue.take(); if (page.isPoisonPill()) break; Iterable<String> words = new Words(page.getText()); for (String word: words) countWord(word); } //因此计数的那个能够是普通的map 他只在本身的线程里 mergeCounts(); } catch (Exception e) { e.printStackTrace(); } } private void countWord(String word) { Integer currentCount = localCounts.get(word); if (currentCount == null) localCounts.put(word, 1); else localCounts.put(word, currentCount + 1); } private void mergeCounts() { for (Map.Entry<String, Integer> e: localCounts.entrySet()) { String word = e.getKey(); Integer count = e.getValue(); while (true) { Integer currentCount = counts.get(word); if (currentCount == null) { if (counts.putIfAbsent(word, count) == null) break; } else if (counts.replace(word, currentCount, currentCount + count)) { break; } } } } }