当前位置: 首页 > 编程日记 > 正文

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邮件列表上进行。我们希望结果包括以下内容:

  1. 改进了形式化。将重新制定基础模型的部分内容。我们的目标是修改后的模型可以进行机械检查,并且更易于人类理解。当根据JLS第17章更新措辞时,这也将解决许多学术论文中指出的现有错误。(最早见 David Aspinall和JaroslavŠevčík撰写的“Java内存模型示例:好,坏,丑”)

  2. JVM覆盖范围。现有规范侧重于语言级构造。这使得一些问题(例如初始化)未完全定义,特别是对于在JVM上运行的其他语言。这些将通过将核心模型建立在最小字节代码和内在函数集上来解决。

  3. 扩展范围。现有规范明确涵盖Java线程,锁,监视器以及volatile和final字段。但是,自Java SE 5以来,添加的功能无法在这些术语中严格指定(例如,AtomicX.weakCompareAndSet)。必须解决这些问题。我们还预计在其他即将到来的JEP过程中可能会出现进一步的扩展。

  4. C11 / C ++ 11兼容性。C ++ 11和C11标准改编了JSR 133 JMM规范工作的想法。但是,他们还扩展了它们以涵盖仅在JSR 133(见上文)之后已经(或可能)添加到Java的构造。部分原因是因为Java程序可能调用C本机库,所以应该是等效结构具有跨语言的兼容规范的情况。我们将进一步探索是否可以建立跨语言约定以确保这些构造的低级实现在公共平台上兼容。

  5. 实施指南。JVM实现者,JDK库开发人员和开发人员通常发现依赖于解释JMM如何影响特定问题和解决方案的文档很有用。我们打算提供这样的文件。

  6. 测试支持。符合内存模型要求很难测试。我们希望与工程师一起设计和实施具有明确规格基础的测试。

  7. 工具支持。重新构建的模型将适合由软件开发工具使用,这些工​​具可以分析性地检查竞争条件等错误,以及检查安全属性是否跨越并发执行的错误。虽然工具本身的设计和构造超出了范围,但是这个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的博客

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

=======================

消息传递和共享内存并发模型之间有什么区别?

这是一个非常简单的区别。在共享内存模型中,多个工作程序都对相同的数据进行操作。这开辟了许多并行编程中常见的并发问题。

消息传递系统使工作人员通过消息系统进行通信。消息使每个人都分开,这样工作人员就无法修改彼此的数据。

  1. 在共享存储器模型中,存储器由协作进程共享,协作进程可以通过读取和写入数据来交换信息,但是在消息传递中,通过在协作进程之间交换的消息进行通信。
  2. 共享内存有助于同时运行进程,但消息传递不能。
  3. 消息传递工具有两个操作:send(消息)和receive(消息)。其过程具有固定或可变的大小。
  4. 消息传递对于交换较少量的数据很有用,因为不需要避免冲突。与用于进程间通信的共享内存相比,消息传递更容易实现。
  5. 在共享内存系统中,仅需要系统调用来建立共享内存区域。一旦建立了共享内存,所有访问都被视为例行内存访问,并且不需要内核的帮助。

共享内存允许最大的通信速度和便利性,因为它可以在计算机内以内存速度完成。共享内存比消息传递更快,因为消息传递系统通常使用系统调用来实现,因此需要更耗时的内核干预任务。

消息传递模型(例如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

相关文章:

ajax实现自动刷新页面实例

html部分&#xff1a;<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>ajax实现自动刷新</title> </head> <body onLoad"Autofresh()"> <p>现在的时间是&#xff1a…

android aliasactivity作用,android activity-alias 的作用

activity-alias是android里为了重复使用Activity而设计的。当在Activity的onCreate()方法里&#xff0c;执行getIntent().getComponent().getClassName();得到的可能不是这个Activity的名字&#xff0c;有可能是别名的名字&#xff0c;例如&#xff1a;在AndroidMenifest.xml有…

1024 程序员节 | 请对身边的程序猿好一点

程序员节起源程序员的工作我们都知道&#xff0c;编程嘛。但为什么程序员节要在1024呢&#xff1f;1024最早火起来是因为一个“不可描述”的论坛&#xff0c;那里的回帖机制是&#xff1a;新用户发过贴之后&#xff0c;过1024秒才能发一贴&#xff0c;如果没到1024秒就又发了一…

stackoverflow上一个最会举例子的专家

https://stackoverflow.com/ Premraj是stackoverflow上一个一个最会举例子的专家&#xff0c;我特意收集了他的一些有趣的举例&#xff1a; Java弱引用最精彩的解释 https://stackoverflow.com/questions/299659/whats-the-difference-between-softreference-and-weakrefere…

Java中的两个关键字——super、this

Java中的两个关键字——super、this 神话丿小王子的博客主页 一、super super 是java中方的一个关键字&#xff0c;用它可以引用父类中的成员&#xff1a; super可用于访问父类中定义的属性 super可用于调用父类中定义的成员方法 super可用于在子类构造器中调用父类的构造器 使…

android system window,Android控件的fitSystemWindows属性

官方描述&#xff1a;根据系统窗体里的元素比如状态栏来调整View的布局。如果被设为true&#xff0c;控件的padding将会被调整为顶部留出一个statusBar的空间。类似于伪代码paddingTop"statusBarHeight"。重点说明&#xff1a;当布局内容可以延伸到状态栏&#xff0c…

Nestjs OpenAPI(Swagger)

官方文档 用来描述api 转载于:https://www.cnblogs.com/ajanuw/p/9846589.html

Jdk11,Jdk12的低延迟垃圾收集器ZGC

https://wiki.openjdk.java.net/display/zgc/Main Z垃圾收集器&#xff0c;也称为ZGC&#xff0c;是一种可扩展的低延迟垃圾收集器&#xff0c;旨在实现以下目标&#xff1a; 暂停时间不超过10毫秒暂停时间不会随堆或实时设置大小而增加处理堆范围从几百M到几T字节大小 一目了…

Android项目驱动式开发教程 第2版,《Android项目驱动式开发教程》第一章开发入门.ppt...

《Android项目驱动式开发教程》第一章开发入门1.4 项目框架分析 4 android:versionName"1.0" > 5 8 第9行代码android:icon用来声明整个APP的图标&#xff0c;图片一般都放在drawable文件夹下&#xff0c;使用资源引用的方式。 第10行代码android:label用来声明整…

getLocationInWindow getLocationOnScreen getLeft , getTop, getBottom,getRight

版权声明&#xff1a;本文为博主原创文章&#xff0c;未经博主允许不得转载。 最近做项目时&#xff0c;发现在activity的onCreate()和onResume()方法里调用View.getLocationInWindow() 时&#xff0c;View.getLocationInWindow()返回空值&#xff0c;觉得很奇怪&#xff0c;因…

使用reflector对.NET反编译

reflector的下载地址&#xff1a;https://www.cr173.com/soft/355285.html 反编译后的结果&#xff1a; 转载于:https://www.cnblogs.com/ZaraNet/p/9848355.html

协程和Java实现

多线程的性能问题&#xff1a; 1.同步锁。 2.线程阻塞状态和可运行状态之间的切换。 3.线程上下文的切换。 协程&#xff0c;英文Coroutines&#xff0c;是一种比线程更加轻量级的存在。正如一个进程可以拥有多个线程一样&#xff0c;一个线程也可以拥有多个协程。 协程&a…

LoadRunner 技巧之 手动关联与预关联

上一节介绍了关联的原理与自动关联&#xff0c;除了自动关联还有另外两种关联方式&#xff1a;手动关联与 预关联。 手动关联 如果脚本很长&#xff0c;那么我们想找到一…

android app文档,android App项目需求描述文档.docx

本app是给外卖配送员用的&#xff0c;系统后台根据一定的逻辑生成或者建立运单&#xff0c;本App读到后台的运单讲外卖送到定外卖的手中本文档所需详细资料请到/s/1jGGgtLG下载与后台交互的地方不用实现&#xff0c;有数据显示的自己把交互函数写好 返回的测试数据写在交互函数…

如何利用微信小游戏的分包加载机制突破4M代码包体积限制

相信大家度过了一个不错的端午假期&#xff0c;在端午前夕&#xff0c;即6月15日晚上&#xff0c;微信小游戏宣布支持分包加载功能&#xff0c;白鹭引擎在端午节后第一天正式支持分包加载机制。在正式向开发者介绍如何使用前&#xff0c;我先为各位解读一下我对微信提供这个 AP…

一个会画图的工程师

发现小谢图画的很好&#xff0c;虽然有些也是他引用的&#xff0c;但是我觉得还是很好所以这里收集下。 【RocketMQ源码学习】2-Namesrv 3-Remoting模块 rocketmq-remoting 模块是 RocketMQ 中负责网络通信的模块&#xff0c;被其他所有需要网络通信的模块依赖。它是基于 Net…

2016百度实习编程题:括号序列

不知如何解决 1.感觉贪心或者动态规划&#xff0c;不知道如何解决 2.做过生成合法括号序列的题目&#xff0c;想到用DFS补成合法的括号&#xff0c;然而没有成功

html动画怎么隐藏,JQuery操作div隐藏和显示的4种动画

Jquery-Div动画显示body{font-family:"宋体";font-size:13px;color:#415973;}#ShowDiv{display:none;width:300px;height:100px;border:1px solid #ccc;border-right:2px solid #888;border-bottom:2px solid #888;background-color:#f9f9f9;text-align:center;paddi…

@芥末的糖----------《后端加密》

bcryptsession 生命周期 session 标识产生的时机和清除时机:&#xff08;权限验证&#xff09; 用户已经登录&#xff1a;这个唯一标识会在用户登录时产生&#xff0c;用户点击退出时或者关闭浏览器时清除。 …

Java中的ClassLoader和SPI机制

深入探讨 Java 类加载器 成富是著名的Java专家&#xff0c;在IBM技术网站发表很多Java好文&#xff0c;也有著作。 线程上下文类加载器 线程上下文类加载器&#xff08;context class loader&#xff09;是从 JDK 1.2 开始引入的。类 java.lang.Thread中的方法 getContextCl…

html在线缓存视频,javascript – 如何为HTML视频添加缓冲

给你的视频提供ID&#xff1a;用于缓冲&#xff1a;var vid document.getElementById("myVideoOne");alert("Start: " vid.buffered.start(0) " End: " vid.buffered.end(0));var vid document.getElementById("myVideoTwo");aler…

ComponentName(String pkg, String cls)

版权声明&#xff1a;本文为博主原创文章&#xff0c;未经博主允许不得转载。 https://blog.csdn.net/qingfeng812/article/details/51279606 开发中因为改项目包名&#xff0c;用了全局替换&#xff0c;误操作把改构造函数的第二个参数只写了类名&#xff0c;不是完整的全路径…

mysql干货——数据库字符集和校对规则详解

2019独角兽企业重金招聘Python工程师标准>>> 一、什么是字符集 字符是多个文字和符号的总称&#xff0c;包括各个国家的文字、标点符号、图形符号、数字等。字符集多个字符的集合。 字符集合种类较多&#xff0c;每个字符集包含的字符的个数不同。对于字符集不支持的…

android监听器在哪里创建,[转载]android开发中创建按钮事件监听器的几种方法

第一种&#xff1a;匿名内部类作为事件监听器类Button button(Button)findViewById(R.id.button);button.setOnClickListener(newOnClickListener(){public void onClick(View v){System.out.println(“匿名内部类作为事件监听类”);}});大部分时候&#xff0c;事件处理器都没有…

Go语言源码分析CAS的实现和Java如出一辙

看了Go的源码CAS这块实现和java还是类似的。 关于Java的分析参考&#xff1a;Java使用字节码和汇编语言同步分析volatile&#xff0c;synchronized的底层实现 都是使用汇编指令&#xff1a;LOCKCMPXCHGL 原因很简单&#xff1a;单核肯定不能发挥Go的高并发性能&#xff0c;G…

python 的文件读写方法:read readline readlines wirte writelines

read()方法读入整个文件&#xff0c;把整个文件以字符串形式返回。readline() 方法每次只读一行&#xff0c;每运行一次只读一行。如果要读整个文件&#xff0c;需要结合循环判断文件结束。python判断文件末尾的标志是&#xff0c;读到空字符。比如&#xff1a;while str ! :r…

c# 模板方法模式

为什么80%的码农都做不了架构师&#xff1f;>>> 既然是模板肯定定义了相同的东西板式&#xff0c;提供了空白的地方自己添加进去就可以了 模板方法是把相同的部分抽象出来到抽象类中去定义&#xff0c;具体子类来实现具体的不同部分&#xff0c;这个思路也正式模板…

transient HashMap使用目的分析

看HashSet源码有这么一句&#xff1a; private transient HashMap<E,Object> map; 再看HashSet的Add方法&#xff1a; 实际上HashSet是复用HashMap了。 而我们去看看HashMap也会发现一样使用了transient 而不管是HashSet还是HashMapdou都要求是Serializable的&#xff…

4月29日监理师课程作业

软考信息系统监理师&#xff1a;2016年4月29日作业一、信息应用系统分析设计阶段监理1、需求分析的进入条件是什么&#xff1f;&#xff08;记&#xff09;答&#xff1a;①业主单位与承建单位正式签订建设合同&#xff0c;②并对初步的项目开发计划达成一致意见。2、需求分析的…

沉浸式导航栏html,混合开发 h5+ 沉浸式的适配

1.需要在mainfest.json plus对象里添加"statusbar": {"immersed": "true","style":"dark"}2.新建immersed.js注意 在里边不适用plus,因为plus.ready之后再js改变样式 必然造成页面闪烁跳动(function(w){document.addEventLi…