JSR 133 Java内存模型以及并发编程的最权威论文汇总
Java內存模型
先看官方文檔:
https://docs.oracle.com/javase/specs/
JSR 133:Java?TM內存模型和線程規范修訂版:https://www.jcp.org/en/jsr/detail?id=133
JSR:Java規范請求所有JSR的列表:https://jcp.org/en/jsr/all
https://www.jcp.org/en/home/index
JSR是Java Specification Requests的縮寫,意思是Java 規范請求。是指向JCP(Java Community Process)提出新增一個標準化技術規范的正式請求。任何人都可以提交JSR,以向Java平臺增添新的API和服務。JSR已成為Java界的一個重要標準。
----------
JSR-000133 Java?TM內存模型和線程規范修訂版?(最終版本):
https://www.jcp.org/aboutJava/communityprocess/final/jsr386/index.html
http://www.cs.umd.edu/~pugh/jmm.pdf
http://openjdk.java.net/jeps/188
該JEP的產品將被放置在?OpenJDK Wiki上。該過程主要在專門的OpenJDK郵件列表上進行。我們希望結果包括以下內容:
-
改進了形式化。將重新制定基礎模型的部分內容。我們的目標是修改后的模型可以進行機械檢查,并且更易于人類理解。當根據JLS第17章更新措辭時,這也將解決許多學術論文中指出的現有錯誤。(最早見?David Aspinall和Jaroslav?ev?ík撰寫的“Java內存模型示例:好,壞,丑”)
-
JVM覆蓋范圍。現有規范側重于語言級構造。這使得一些問題(例如初始化)未完全定義,特別是對于在JVM上運行的其他語言。這些將通過將核心模型建立在最小字節代碼和內在函數集上來解決。
-
擴展范圍。現有規范明確涵蓋Java線程,鎖,監視器以及volatile和final字段。但是,自Java SE 5以來,添加的功能無法在這些術語中嚴格指定(例如,AtomicX.weakCompareAndSet)。必須解決這些問題。我們還預計在其他即將到來的JEP過程中可能會出現進一步的擴展。
-
C11 / C ++ 11兼容性。C ++ 11和C11標準改編了JSR 133 JMM規范工作的想法。但是,他們還擴展了它們以涵蓋僅在JSR 133(見上文)之后已經(或可能)添加到Java的構造。部分原因是因為Java程序可能調用C本機庫,所以應該是等效結構具有跨語言的兼容規范的情況。我們將進一步探索是否可以建立跨語言約定以確保這些構造的低級實現在公共平臺上兼容。
-
實施指南。JVM實現者,JDK庫開發人員和開發人員通常發現依賴于解釋JMM如何影響特定問題和解決方案的文檔很有用。我們打算提供這樣的文件。
-
測試支持。符合內存模型要求很難測試。我們希望與工程師一起設計和實施具有明確規格基礎的測試。
-
工具支持。重新構建的模型將適合由軟件開發工具使用,這些工??具可以分析性地檢查競爭條件等錯誤,以及檢查安全屬性是否跨越并發執行的錯誤。雖然工具本身的設計和構造超出了范圍,但是這個JEP可以為注釋提供指導,以實現高質量的靜態和動態分析。
------------------------------------
The Java Memory Model:http://www.cs.umd.edu/users/pugh/java/memoryModel/
Java內存模型
該網頁是討論Java內存模型和Java語言規范第17章的信息的起點。Java Memory Model定義了線程如何通過內存進行交互。過去有點不清楚和不必要的限制,因此進行了修訂。這是該修訂的參考頁面。JSR 133的官方站點 - Java(tm)內存模型和線程規范修訂版 -?就在這里。
此頁面分為幾個部分:
- 內存模型上的主要參考資料。
- 指向郵件列表和檔案的指針。
- 內存模型上的其他材料,包括有關雙重檢查鎖定的信息。
- 內存模型上的舊材料現已過時。
- 指示進一步閱讀其他來源的材料。
參考資料
對于試圖理解內存模型的人來說,這些參考資料是一個很好的起點。在它們之間,它們涵蓋了所涉及的大多數主要問題。
- 對于初次訪客
- 一個?程序員JSR-133 FAQ資源是可用的。對于那些剛剛意識到這些問題的人來說,這是一個很好的起點。(2004年2月11日)
?
- 對于JVM和編譯器實現者
- Doug Lea的JSR-133烹飪書,是希望實現Java內存模型的編譯器編寫者的指南。
- Sarita Adve和Kourosh Gharachorloo在1995年撰寫了關于記憶模型的教程,這仍然是一本很好的參考和入門書。Compaq Research Report 95/7,1995年9月,?95.7 - 共享內存一致性模型:教程。
?
- 對于那些希望完全了解內存模型的人
- 關于記憶模型的?期刊提交,結合了Jeremy Manson的論文,POPL論文和CSJP論文。對于那些對內存模型問題有深入討論感興趣的人來說,這是最好的選擇。(2005年10月7日)。
- JSR-133規范,發送到最終批準選票。這是“官方規范”(2004年8月9日)。它的解釋方式并不多。
- 最終字段語義的新表示/描述。這是最終字段語義的簡要描述。(2004年5月12日)
JSR 133(Java內存模型)常見問題解答:https://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html
JSR 133(Java內存模型)常見問題解答
Jeremy Manson和Brian Goetz,2004年2月
目錄
- 無論如何,什么是記憶模型?
- 其他語言,比如C ++,有內存模型嗎?
- 什么是JSR 133?
- 重新排序是什么意思?
- 舊的記憶模型出了什么問題?
- 錯誤同步是什么意思?
- 同步有什么作用?
- 最終字段如何顯示更改其值?
- 最終字段如何在新的JMM下工作?
- 揮發物有什么作用?
- 新內存模型是否修復了“雙重檢查鎖定”問題?
- 如果我正在編寫VM怎么辦?
- 我為什么要在乎?
------------
“雙重檢查鎖定”聲明
Double-Checked Locking被廣泛引用并用作在多線程環境中實現延遲初始化的有效方法。
不幸的是,當在Java中實現時,它將無法以獨立于平臺的方式可靠地工作,而無需額外的同步。當用其他語言(如C ++)實現時,它取決于處理器的內存模型,編譯器執行的重新排序以及編譯器和同步庫之間的交互。由于這些都不是用C ++這樣的語言指定的,因此對它的工作情況幾乎沒有什么可說的。可以使用顯式內存屏障使其在C ++中工作,但這些障礙在Java中不可用。
-----------------------
同步和Java內存模型
JSR-133編寫器編寫手冊
輕松內存并發
多處理器現在已經普及,并發編程正在成為主流,但典型的多處理器(x86,Sparc,Power,ARM,Itanium)和編程語言(C,C ++,Java)不能提供大多數工作所假設的順序一致的共享內存。關于語義和驗證。相反,他們有微妙的放松?(或弱)內存模型,暴露出對程序員的硬件和編譯器優化所產生的行為。而且,這些記憶模型通常只在含糊不清(有時有缺陷)的散文中描述,導致廣泛的混淆。該頁面收集了一組人員的工作,他們致力于為多處理器程序開發數學上嚴格且可用的語義。我們主要關注三種處理器架構(x86,Power和ARM),最近的C ++和C語言版本(C ++ 11和C11),以及使用這些模型的推理和驗證。
英特爾?64和IA-32架構軟件開發人員手冊
Fixing the Java Memory Model, Part 1
Fixing the Java Memory Model, Part 2
Going atomic
-------------
https://hllvm-group.iteye.com/group/topic/21468?
| RednaxelaFX?2010-09-11 |
關于VM的帖的目錄?
==============
視頻:《Java Memory Model in 10 minutes》?
《Java ExecutorService - Part 1 - Introduction》
https://www.youtube.com/channel/UCiz26UeGvcTy4_M3Zhgk7FQ
?
重排序
編譯器只保證單線程下沒問題滿足?happens-before,但是單線程下沒有happens-before的多線程下會出現重排序指令從而導致不可預期的問題
public class PossibleReordering {static int x, y;static int a, b;public static void main(String[] args) throws InterruptedException {for (int i = 0; i < 20; i++) {x = 0;y = 0;a = 0;b = 0;Thread one = new Thread(new Runnable() {public void run() {a = 1;x = b;System.out.println("one run");}});Thread other = new Thread(new Runnable() {public void run() {b = 1;y = a;System.out.println("other run");}});System.out.println("one.start()>>>");one.start();System.out.println("other.start()>>>");other.start();System.out.println("one.join()>>>");one.join();System.out.println("other.join()>>>");other.join();System.out.println(i + " x=" + x + ",y=" + y);System.out.println("===============================");}}
}
為什么加join是因為你不加join,main的主線程先執行,這樣輸出的就不是xy的真實結果而是過程中的數據,所以要先等自線程結束:
第一個線程先執行等第二個線程
如果循環1000次會看出更多的這種不一致。?
?
那么其實程序員想要的是xy需要等ab賦值完成再去賦值,這樣就涉及同步,
使用CyclicBarrier就可以很好的完成這個任務:
import java.util.concurrent.CyclicBarrier;public class PossibleReordering {static int x, y;static int a, b;public static void main(String[] args) throws InterruptedException {for (int i = 0; i < 1000; i++) { CyclicBarrier barrier = new CyclicBarrier(2);x = 0;y = 0;a = 0;b = 0;Thread one = new Thread(new Runnable() {public void run() {a = 1;try {barrier.await();} catch (Exception ex) {System.out.println("異常"+ex.toString());} x = b;System.out.println("one run");}});Thread other = new Thread(new Runnable() {public void run() {b = 1;try {barrier.await();} catch (Exception ex) {System.out.println("異常"+ex.toString());} y = a;System.out.println("other run");}});System.out.println("one.start()>>>");one.start();System.out.println("other.start()>>>");other.start();System.out.println("one.join()>>>");one.join();System.out.println("other.join()>>>");other.join();System.out.println(i + " x=" + x + ",y=" + y);System.out.println("===============================");}}
}
從結果可以看出是1000次都是x=1,y=1的。
如果 不寫上join
one.join();
other.join();
如果不加上join其實會看不到真實的結果,不便于測試的驗證,當然了這樣是不是反而加深了對join的理解呢??
參考:JVM(十一)Java指令重排序???Java并發編程--CyclicBarrier
我覺得這幅圖畫的很好,對多線程理解起來很有幫助:
?
?
針對前面main函數必須加join等待的情況其實可以使用?CountDownLatch更優雅的實現:
/** To change this license header, choose License Headers in Project Properties.* To change this template file, choose Tools | Templates* and open the template in the editor.*/
package com.current.www;import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;public class PossibleReordering {static int x, y;static int a, b;public static void main(String[] args) throws InterruptedException {for (int i = 0; i < 1000; i++) { CountDownLatch latch = new CountDownLatch(2);CyclicBarrier barrier = new CyclicBarrier(2);x = 0;y = 0;a = 0;b = 0;Thread one = new Thread(new Runnable() {public void run() {a = 1;try {barrier.await();} catch (Exception ex) {System.out.println("異常"+ex.toString());} x = b;latch.countDown();}});Thread other = new Thread(new Runnable() {public void run() {b = 1;try {barrier.await();} catch (Exception ex) {System.out.println("異常"+ex.toString());} y = a;latch.countDown();}});one.start();other.start();latch.await();System.out.println(i + " x=" + x + ",y=" + y);System.out.println("===============================");}}
}
至此這個例子也比較好的解釋了?CountDownLatch和CyclicBarrier的差異。
我給出一個總結就是:
CyclicBarrier是線程內部等待,CountDownLatch是線程外等待。
?
下面看看CyclicBarrier的源碼:
/** ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.*********************//******* Written by Doug Lea with assistance from members of JCP JSR-166* Expert Group and released to the public domain, as explained at* http://creativecommons.org/publicdomain/zero/1.0/*/package java.util.concurrent;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;/*** A synchronization aid that allows a set of threads to all wait for* each other to reach a common barrier point. CyclicBarriers are* useful in programs involving a fixed sized party of threads that* must occasionally wait for each other. The barrier is called* <em>cyclic</em> because it can be re-used after the waiting threads* are released.** <p>A {@code CyclicBarrier} supports an optional {@link Runnable} command* that is run once per barrier point, after the last thread in the party* arrives, but before any threads are released.* This <em>barrier action</em> is useful* for updating shared-state before any of the parties continue.** <p><b>Sample usage:</b> Here is an example of using a barrier in a* parallel decomposition design:** <pre> {@code* class Solver {* final int N;* final float[][] data;* final CyclicBarrier barrier;** class Worker implements Runnable {* int myRow;* Worker(int row) { myRow = row; }* public void run() {* while (!done()) {* processRow(myRow);** try {* barrier.await();* } catch (InterruptedException ex) {* return;* } catch (BrokenBarrierException ex) {* return;* }* }* }* }** public Solver(float[][] matrix) {* data = matrix;* N = matrix.length;* Runnable barrierAction =* new Runnable() { public void run() { mergeRows(...); }};* barrier = new CyclicBarrier(N, barrierAction);** List<Thread> threads = new ArrayList<Thread>(N);* for (int i = 0; i < N; i++) {* Thread thread = new Thread(new Worker(i));* threads.add(thread);* thread.start();* }** // wait until done* for (Thread thread : threads)* thread.join();* }* }}</pre>** Here, each worker thread processes a row of the matrix then waits at the* barrier until all rows have been processed. When all rows are processed* the supplied {@link Runnable} barrier action is executed and merges the* rows. If the merger* determines that a solution has been found then {@code done()} will return* {@code true} and each worker will terminate.** <p>If the barrier action does not rely on the parties being suspended when* it is executed, then any of the threads in the party could execute that* action when it is released. To facilitate this, each invocation of* {@link #await} returns the arrival index of that thread at the barrier.* You can then choose which thread should execute the barrier action, for* example:* <pre> {@code* if (barrier.await() == 0) {* // log the completion of this iteration* }}</pre>** <p>The {@code CyclicBarrier} uses an all-or-none breakage model* for failed synchronization attempts: If a thread leaves a barrier* point prematurely because of interruption, failure, or timeout, all* other threads waiting at that barrier point will also leave* abnormally via {@link BrokenBarrierException} (or* {@link InterruptedException} if they too were interrupted at about* the same time).** <p>Memory consistency effects: Actions in a thread prior to calling* {@code await()}* <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>* actions that are part of the barrier action, which in turn* <i>happen-before</i> actions following a successful return from the* corresponding {@code await()} in other threads.** @since 1.5* @see CountDownLatch** @author Doug Lea*/
public class CyclicBarrier {/*** Each use of the barrier is represented as a generation instance.* The generation changes whenever the barrier is tripped, or* is reset. There can be many generations associated with threads* using the barrier - due to the non-deterministic way the lock* may be allocated to waiting threads - but only one of these* can be active at a time (the one to which {@code count} applies)* and all the rest are either broken or tripped.* There need not be an active generation if there has been a break* but no subsequent reset.*/private static class Generation {boolean broken = false;}/** The lock for guarding barrier entry */private final ReentrantLock lock = new ReentrantLock();/** Condition to wait on until tripped */private final Condition trip = lock.newCondition();/** The number of parties */private final int parties;/* The command to run when tripped */private final Runnable barrierCommand;/** The current generation */private Generation generation = new Generation();/*** Number of parties still waiting. Counts down from parties to 0* on each generation. It is reset to parties on each new* generation or when broken.*/private int count;/*** Updates state on barrier trip and wakes up everyone.* Called only while holding lock.*/private void nextGeneration() {// signal completion of last generationtrip.signalAll();// set up next generationcount = parties;generation = new Generation();}/*** Sets current barrier generation as broken and wakes up everyone.* Called only while holding lock.*/private void breakBarrier() {generation.broken = true;count = parties;trip.signalAll();}/*** Main barrier code, covering the various policies.*/private int dowait(boolean timed, long nanos)throws InterruptedException, BrokenBarrierException,TimeoutException {final ReentrantLock lock = this.lock;lock.lock();try {final Generation g = generation;if (g.broken)throw new BrokenBarrierException();if (Thread.interrupted()) {breakBarrier();throw new InterruptedException();}int index = --count;if (index == 0) { // trippedboolean ranAction = false;try {final Runnable command = barrierCommand;if (command != null)command.run();ranAction = true;nextGeneration();return 0;} finally {if (!ranAction)breakBarrier();}}// loop until tripped, broken, interrupted, or timed outfor (;;) {try {if (!timed)trip.await();else if (nanos > 0L)nanos = trip.awaitNanos(nanos);} catch (InterruptedException ie) {if (g == generation && ! g.broken) {breakBarrier();throw ie;} else {// We're about to finish waiting even if we had not// been interrupted, so this interrupt is deemed to// "belong" to subsequent execution.Thread.currentThread().interrupt();}}if (g.broken)throw new BrokenBarrierException();if (g != generation)return index;if (timed && nanos <= 0L) {breakBarrier();throw new TimeoutException();}}} finally {lock.unlock();}}/*** Creates a new {@code CyclicBarrier} that will trip when the* given number of parties (threads) are waiting upon it, and which* will execute the given barrier action when the barrier is tripped,* performed by the last thread entering the barrier.** @param parties the number of threads that must invoke {@link #await}* before the barrier is tripped* @param barrierAction the command to execute when the barrier is* tripped, or {@code null} if there is no action* @throws IllegalArgumentException if {@code parties} is less than 1*/public CyclicBarrier(int parties, Runnable barrierAction) {if (parties <= 0) throw new IllegalArgumentException();this.parties = parties;this.count = parties;this.barrierCommand = barrierAction;}/*** Creates a new {@code CyclicBarrier} that will trip when the* given number of parties (threads) are waiting upon it, and* does not perform a predefined action when the barrier is tripped.** @param parties the number of threads that must invoke {@link #await}* before the barrier is tripped* @throws IllegalArgumentException if {@code parties} is less than 1*/public CyclicBarrier(int parties) {this(parties, null);}/*** Returns the number of parties required to trip this barrier.** @return the number of parties required to trip this barrier*/public int getParties() {return parties;}/*** Waits until all {@linkplain #getParties parties} have invoked* {@code await} on this barrier.** <p>If the current thread is not the last to arrive then it is* disabled for thread scheduling purposes and lies dormant until* one of the following things happens:* <ul>* <li>The last thread arrives; or* <li>Some other thread {@linkplain Thread#interrupt interrupts}* the current thread; or* <li>Some other thread {@linkplain Thread#interrupt interrupts}* one of the other waiting threads; or* <li>Some other thread times out while waiting for barrier; or* <li>Some other thread invokes {@link #reset} on this barrier.* </ul>** <p>If the current thread:* <ul>* <li>has its interrupted status set on entry to this method; or* <li>is {@linkplain Thread#interrupt interrupted} while waiting* </ul>* then {@link InterruptedException} is thrown and the current thread's* interrupted status is cleared.** <p>If the barrier is {@link #reset} while any thread is waiting,* or if the barrier {@linkplain #isBroken is broken} when* {@code await} is invoked, or while any thread is waiting, then* {@link BrokenBarrierException} is thrown.** <p>If any thread is {@linkplain Thread#interrupt interrupted} while waiting,* then all other waiting threads will throw* {@link BrokenBarrierException} and the barrier is placed in the broken* state.** <p>If the current thread is the last thread to arrive, and a* non-null barrier action was supplied in the constructor, then the* current thread runs the action before allowing the other threads to* continue.* If an exception occurs during the barrier action then that exception* will be propagated in the current thread and the barrier is placed in* the broken state.** @return the arrival index of the current thread, where index* {@code getParties() - 1} indicates the first* to arrive and zero indicates the last to arrive* @throws InterruptedException if the current thread was interrupted* while waiting* @throws BrokenBarrierException if <em>another</em> thread was* interrupted or timed out while the current thread was* waiting, or the barrier was reset, or the barrier was* broken when {@code await} was called, or the barrier* action (if present) failed due to an exception*/public int await() throws InterruptedException, BrokenBarrierException {try {return dowait(false, 0L);} catch (TimeoutException toe) {throw new Error(toe); // cannot happen}}/*** Waits until all {@linkplain #getParties parties} have invoked* {@code await} on this barrier, or the specified waiting time elapses.** <p>If the current thread is not the last to arrive then it is* disabled for thread scheduling purposes and lies dormant until* one of the following things happens:* <ul>* <li>The last thread arrives; or* <li>The specified timeout elapses; or* <li>Some other thread {@linkplain Thread#interrupt interrupts}* the current thread; or* <li>Some other thread {@linkplain Thread#interrupt interrupts}* one of the other waiting threads; or* <li>Some other thread times out while waiting for barrier; or* <li>Some other thread invokes {@link #reset} on this barrier.* </ul>** <p>If the current thread:* <ul>* <li>has its interrupted status set on entry to this method; or* <li>is {@linkplain Thread#interrupt interrupted} while waiting* </ul>* then {@link InterruptedException} is thrown and the current thread's* interrupted status is cleared.** <p>If the specified waiting time elapses then {@link TimeoutException}* is thrown. If the time is less than or equal to zero, the* method will not wait at all.** <p>If the barrier is {@link #reset} while any thread is waiting,* or if the barrier {@linkplain #isBroken is broken} when* {@code await} is invoked, or while any thread is waiting, then* {@link BrokenBarrierException} is thrown.** <p>If any thread is {@linkplain Thread#interrupt interrupted} while* waiting, then all other waiting threads will throw {@link* BrokenBarrierException} and the barrier is placed in the broken* state.** <p>If the current thread is the last thread to arrive, and a* non-null barrier action was supplied in the constructor, then the* current thread runs the action before allowing the other threads to* continue.* If an exception occurs during the barrier action then that exception* will be propagated in the current thread and the barrier is placed in* the broken state.** @param timeout the time to wait for the barrier* @param unit the time unit of the timeout parameter* @return the arrival index of the current thread, where index* {@code getParties() - 1} indicates the first* to arrive and zero indicates the last to arrive* @throws InterruptedException if the current thread was interrupted* while waiting* @throws TimeoutException if the specified timeout elapses.* In this case the barrier will be broken.* @throws BrokenBarrierException if <em>another</em> thread was* interrupted or timed out while the current thread was* waiting, or the barrier was reset, or the barrier was broken* when {@code await} was called, or the barrier action (if* present) failed due to an exception*/public int await(long timeout, TimeUnit unit)throws InterruptedException,BrokenBarrierException,TimeoutException {return dowait(true, unit.toNanos(timeout));}/*** Queries if this barrier is in a broken state.** @return {@code true} if one or more parties broke out of this* barrier due to interruption or timeout since* construction or the last reset, or a barrier action* failed due to an exception; {@code false} otherwise.*/public boolean isBroken() {final ReentrantLock lock = this.lock;lock.lock();try {return generation.broken;} finally {lock.unlock();}}/*** Resets the barrier to its initial state. If any parties are* currently waiting at the barrier, they will return with a* {@link BrokenBarrierException}. Note that resets <em>after</em>* a breakage has occurred for other reasons can be complicated to* carry out; threads need to re-synchronize in some other way,* and choose one to perform the reset. It may be preferable to* instead create a new barrier for subsequent use.*/public void reset() {final ReentrantLock lock = this.lock;lock.lock();try {breakBarrier(); // break the current generationnextGeneration(); // start a new generation} finally {lock.unlock();}}/*** Returns the number of parties currently waiting at the barrier.* This method is primarily useful for debugging and assertions.** @return the number of parties currently blocked in {@link #await}*/public int getNumberWaiting() {final ReentrantLock lock = this.lock;lock.lock();try {return parties - count;} finally {lock.unlock();}}
}
很容易發現使用了ReentrantLock,最主要就是dowait方法。
一開始初始化CyclicBarrier
就是初始化計數器,直到每個parties 變成0
起了3個線程:
先進入線程0 ,可以看到計數器是2。
?
進入dowait,拿到鎖:
執行到trip.await()讓出鎖:
?
這時候再進入線程1:
由于經過2次--操作計數已經是0,所以進入if (index == 0) { ?// tripped
?一直執行到unlock之前,在這之前線程0都是等待被喚醒,如圖所示。
?
當線程1執行了其實unlock之后其實線程0已經喚醒,線程1繼續往下執行。
如果這時候切回主函數可以看到線程0已經跳出await了:
這時候線程0已經可以去執行下面的操作,因為已經到了安全屏障之后。
線程1回到主函數,然后也是和線程0一樣去執行下面的操作,因為也已經到了安全屏障之后。
再總結下思路其實就是產生一個計數,然后每個線程都要同步加鎖?-1,減完之后等待其他線程-1,等于0的時候喚醒全部線程繼續往下執行。
?
需要注意的是在IDEA下需要設置所有的多線程涉及的斷點需要設置為Thead,否則多線程調試很難達到你想要的效果,也就是會直接跳過其他線程。
==================
再來看看Go語言中的一些處理并發問題的哲學,其實思想都是相通的:
Share Memory By Communicating
Go的并發方法與線程和共享內存的傳統使用不同。從哲學上講,可以概括為:?
不要通過共享內存來通信,而應該通過通信來共享內存。
通道允許您將引用傳遞給goroutines之間的數據結構。如果您認為這是傳遞數據的所有權(讀取和寫入數據的能力),它們將成為一種強大而富有表現力的同步機制。?
Share Memory By Communicating
=======================
消息傳遞和共享內存并發模型之間有什么區別?
這是一個非常簡單的區別。在共享內存模型中,多個工作程序都對相同的數據進行操作。這開辟了許多并行編程中常見的并發問題。
消息傳遞系統使工作人員通過消息系統進行通信。消息使每個人都分開,這樣工作人員就無法修改彼此的數據。
- 在共享存儲器模型中,存儲器由協作進程共享,協作進程可以通過讀取和寫入數據來交換信息,但是在消息傳遞中,通過在協作進程之間交換的消息進行通信。
- 共享內存有助于同時運行進程,但消息傳遞不能。
- 消息傳遞工具有兩個操作:send(消息)和receive(消息)。其過程具有固定或可變的大小。
- 消息傳遞對于交換較少量的數據很有用,因為不需要避免沖突。與用于進程間通信的共享內存相比,消息傳遞更容易實現。
- 在共享內存系統中,僅需要系統調用來建立共享內存區域。一旦建立了共享內存,所有訪問都被視為例行內存訪問,并且不需要內核的幫助。
共享內存允許最大的通信速度和便利性,因為它可以在計算機內以內存速度完成。共享內存比消息傳遞更快,因為消息傳遞系統通常使用系統調用來實現,因此需要更耗時的內核干預任務。
消息傳遞模型(例如Erlang)沒有任何共享狀態;?通過交換消息完成所有同步和通信。共享內存模型通過讀/寫共享內存塊進行通信,共享內存塊受信號量或類似內容的保護。
對于某些需要快速響應時間的應用程序,消息傳遞系統的吞吐量可能太低,但如果您需要更高的速度或實時處理,則可以使用共享內存系統。
----
區分Java線程和OS線程?
?
在Linux上,Java線程是使用本機線程實現的,因此使用線程的Java程序與使用線程的本機程序沒有什么不同。“Java線程”只是屬于JVM進程的線程。
在現代Linux系統(使用NPTL的系統)上,屬于進程的所有線程具有相同的進程ID和父進程ID,但具有不同的線程ID。您可以通過運行查看這些ID?ps -eLf。PID列是進程ID,PPID列是父進程ID,LWP列是線程(LightWeight進程)ID。“main”線程的線程ID與進程ID相同,其他線程將具有不同的線程ID值。
較舊的Linux系統可能使用“linuxthreads”線程實現,而不是完全符合POSIX,而不是NPTL。在linuxthreads系統上,線程具有不同的進程ID。
您可以通過將系統的C庫(libc)作為獨立程序運行并查看其輸出中的“Available extensions”來檢查您的系統是使用NPTL還是linuxthreads。它應該提到“Native POSIX Threads Library”或linuxthreads。到C庫中的路徑改變因系統:它可以是/lib/libc.so.6,/lib64/libc.so.6(在64位為基礎的RedHat系統中),或類似的東西/lib/x86_64-linux-gnu/libc.so.6(在現代基于Debian的系統如Ubuntu)。
在操作系統級別,theads沒有名稱;?那些只存在于JVM中。
在pthread_kill()C函數可以被用來把信號發送到特定線程,你可以用它來試圖殺死特定線程從JVM外面,但我不知道JVM將如何回應。它可能會殺死整個JVM。
?
《內存屏障與 JVM 并發》
內存屏障,又稱內存柵欄,是一組處理器指令,用于實現對內存操作的順序限制。
內存屏障不直接由 JVM 暴露,相反它們被 JVM 插入到指令序列中以維持語言層并發原語的語義。
內存屏障是多線程編程的必要裝備。它們形式多樣,某些是顯式的,某些是隱式的。某些是雙向的,某些是單向的。JVM 利用這些形式在所有平臺中有效地支持 Java 內存模型。
=========================
Java并發和多線程教程
線程池&阻塞隊列實現--筆記
=========================
推薦3本并行編程的書:
1.入門的,《The Little Book of Semaphores》信號量小書
信號量小書是一本免費的(在兩個意義上)教科書,它介紹了并發編程的同步原理。
在大多數計算機科學課程中,同步是操作系統類中的一個模塊。
操作系統教科書使用一套標準的解決方案提出了一系列標準問題,但是大多數學生并沒有很好地理解材料或解決類似問題的能力。
本書的方法是識別對各種同步問題有用的模式,然后展示如何將它們組合成解決方案。在每個問題出現后,本書在提供解決方案之前提供了一個提示,讓學生有更好的機會自己發現解決方案。
http://greenteapress.com/semaphores/
這里有人翻譯好的中文版:https://blog.csdn.net/booksyhay/article/category/8055255/2?
2. RCU的作者,大牛Paul E. McKenney寫的書,“并行編程很難,如果是這樣,你能做些什么呢??”。
https://mirrors.edge.kernel.org/pub/linux/kernel/people/paulmck/perfbook/perfbook.html
3.七周七并發模型
http://www.ituring.com.cn/book/1649
總結
以上是生活随笔為你收集整理的JSR 133 Java内存模型以及并发编程的最权威论文汇总的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 我和我的祖国电影在哪里播出
- 下一篇: stackoverflow上一个最会举例