xl_echo가, 다시 인쇄에 오신 것을 환영합니다, 편집 기사의 소스를 선언하십시오. 학습의 교환 : 에코 마이크로 편지 (t2421499075 마이크로 신호)를 추가 할 오신 것을 환영합니다. 전투, 무패 승리 주장하지에 따라, 패배 후 패배는 전진 어려움을 겪고 에너지에 따르면, 퇴폐적 없습니다. - 이것은 실제 정격 전력입니다! !
참고 도서 : "자바 높은 동시 프로그래밍을 설명합니다." 이 책의 해당 지식을 보려면, 다음 발췌 한이 책의 내용이 표시되어 원래의 유료 지원 지식을 존중, 원래 책을 구입하시기 바랍니다.
기사의 참조 목록 :
휘발성 물질
무엇 휘발성
언급 된 동기와 비교 휘발성 휘발성 경량 잠금 및 동기화의 의미 구성 요소를 실현할 수 있습니다. 그것은 멀티 스레드 공유 자원의 가시성을 보장하기 위해,이 기능은 다른 변수는 공유 변수의 값을 읽을 수있을 때 하나 개의 공유 변수를 적용 할 스레드로 주요 이해 될 수있다 다루는 것입니다.
코드 가시성에서 자원 아무 문제 없습니다
이념적 코드 관측에 프로그램을 이해하는 첫 번째 원칙을 바탕으로, 우리는 다음과 같은 코드, 이해의 휘발성 염기의 첫 번째 징후를 관찰 할 수있다.
에서 다음 코드 발췌
public class VolatileFoo {
final static int MAX = 5;
static int init_value = 0;
//static volatile int init_value = 0;
public static void main(String[] args) {
new Thread(() -> {
int localValue = init_value;
while (localValue < MAX) {
if (init_value != localValue) {
System.out.printf("The init_value is update to [%d]\n", init_value);
localValue = init_value;
}
}
}, "Reader").start();
new Thread(() -> {
int localValue = init_value;
while (localValue < MAX) {
System.out.printf("The init_value will be changed to [%d]\n", ++localValue);
init_value = localValue;
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "Updater").start();
}
}
우리는 휘발성의 경우를 이해하지 못한다면, 우리는 위의 코드는이 구현이 지속적으로 교대로 출력 변수 함수 두 개의 스레드 만듭니다이라고 생각합니다 것을 알 수 있습니다. 순환하는 동안이 끝날 때까지, localValue까지 동일한 5시에, 않습니다 끊임없이 localValue 변경되는 코드를보세요. 그러나 우리는 다음과 같은 결과를 볼 수 있고, 결론은 우리 증명하기 위해 여기에없는 결론의 잘못을
실제 출력 우리 업데이터 스레드의 결과 localValue = 5, 우리 업데이터 스레드 사이클을 종료한다 출력왔다이다. 우리의 리더 스레드가 실행되고 무한 루프의 상태에있다. 여기에 우리가 스레드가 변경되지 않은 읽어야 localValue 리더의 값을 볼 수 있습니다, 분명히 문제를 볼 수 있습니다 독자 스레드가이로하지 않습니다 후 두 스레드는 변수에 액세스, 업데이 변수 값을 변경 즉, 값의 변화.
휘발성 첫 경험
이 변수 가시성을 공유의 상기와 같은 문제점 후, 우리는 중요성을 볼 수 있습니다 위의 프로그램 문제 해결은 당신이 위의 작은 수정을 할 필요가 실제로 비교적 간단하다. 수정 휘발성 init_value의 사용, 다른 변경, 우리는 다시 한 번 출력을 확인합니다.
우리는 업데이터 스레드 init_value가 변경된 출력에 의해 볼 수 있습니다, 우리 리더 스레드 효과적으로 출력과 리더 스레드 init_value 관찰 된 결과와 함께,이 변수의 변화를 관찰했다. 위는 동일하지 않습니다하고 코드를 효과적으로 프로그램을 종료 할 수
> CPU 하드웨어 및 운영 JMM 메모리 모델 - 인사이트 휘발성, 그리고 효과적인 방법은 이해의 필요성을 파악해야 할 필요성을 인식한다. CPU와 우리가 실행하는 프로그램 사이의 관계는 우리가 이러한 점을 표시 마스터하는 방법 휘발성 필수 필요성을 이해하도록 바닥이 잘못된 방법의 일종이다.
관계 프로그램 우리가 작성하고 CPU에 의해 실행
우리의 프로그램이 실행되고, 우리는 프로그램이 프로세스는 효과를 통해 이동합니다 CPU에 의해 실행되는 디스크, 메모리 부하, CPU 액세스 실행에 기록. 이 하드 드라이브, 메모리와 CPU 사이의 큰 차이.
- 하드 디스크 : 데이터 저장 장비 및 소프트웨어 및 기타 데이터는 용량, 전력 데이터는 문자가 삭제되지 않고있다. 또한으로 알려진 "데이터웨어 하우스." 우리는 내부의 하드 디스크에 저장되어있는 프로그램을 작성
- 内存:1. 负责硬盘等硬件上的数据与CPU之间数据交换处理;2. 缓存系统中的临时数据。3. 断电后数据丢失。可以称为他就是硬盘和CPU之间的桥梁,并且我们的程序编写完成存储到硬盘中之后,开始执行就会被加载进入内存,并等待CPU对内存进行寻址操作。
- CPU:中央处理单元(Cntral Pocessing Uit)的缩写,也叫处理器,是计算机的运算核心和控制核心。执行我们编写的代码CPU只是接收到执行指令,然后对内存进行寻址操作。
硬盘、内存和CPU的存取速度是递增的,内存比硬盘要快很多,但是CPU又比内存块很多倍,CPU的存取速度快到内存都跟不上,所以在CPU和内存之间出现了一个新的东西,那就是CPU Cache。cache的容量远远小于主存,因此出现cache miss在所难免,这也是我们为什么会出现数据问题的关键所在。
CPU cache结构及cache操作数据导致数据不一致的问题
CPU中cache的结构我们可以打开任务管理器,点击性能即可以看到。多核CPU的结构与单核相似,但是多了所有CPU共享的L3三级缓存。在多核CPU的结构中,L1和L2是CPU私有的,L3则是所有CPU核心共享的。
在我们的系统中,由于短板效应,导致即时我们CPU速度再快也没有办法发挥它的能力。由于内存的读取速度远低于CPU,所以导致我们的程序执行速度,被内存限制。但是当cache出现之后完全改变了这个情况,它极大的增大了CPU的吞吐量。CPU只需要到cache中进行读取和写入操作即可,cache会在之后将结果同步到内存。但是当多线程情况下就会出现问题,每个线程都有自己的工作内存,本地内存,对应CPU中Cache。当多个线程同时操作一个变量的时候,都会进行读取到CPU Cache当中,然后在同步会主内存,这样就会导致数据结果不一致。也就是我们平时看到的,多线程结果与预期不一致的问题。
Java内存模型
Java的内存模型(Java Memory Mode)制定了Java虚拟机如何与计算机的主存进行工作,理解Java内存模型对于编写并发程序非常重要。在CPU cache当中我们使用文字描述了多线程情况下出现结果不一致情况,这里我们可以通过Java内存模型的图解来更直观的看到这个情况是怎么出现的。
图中线程1的工作内存和线程2的工作内存就是我们上面描述的当有多个线程操作一个变量时,每个线程就会将变量复制一份到自己的工作内存当中。当我们的多线程执行的时候,每一个线程赋值一份变量,都对值进行修改,当共享变量不可见的时候,最终就会导致结果不一致。
并发编程的三个重要特性
- 原子性
-
- 原型性是指一个操作的完整性,要么该操作改变的值或者资源全部成功,要么全部不成功。
- 有序性
-
- 所谓有序性就是指代码在执行过程当中的先后顺序。
- 可见性
-
- 可见性在我们最上面的例子里面就展现了,就是一个线程修改共享变量的值的时候,另外一个线程能够看到这个变量的值被改变。
在我们多线程并发编程当中,它的三大特性是保证并发执行不出现错误的关键,volatile我们目前能够看到在并发编程当中能够保证可见性。除了可见性外还其实它还可以保证有序性,只是不能保证原子性而已。假若能够保证原子性,它和synchronize的作用基本那就是一样的,只是底层的实现原理不一样而已。
volatile如何保证有序性(摘抄)
volatile关键字对顺序性的保证就比较霸道,直接禁止JVM和处理器对volatile关键字修饰的指令重新排序,但是对于volatile前后无依赖关系的指令则可以随便怎么排序。
volatile可见性的底层实现原理
volatile底层的实现其实是通过lock关键字进行实现的,我们可以去获取class的汇编码,当使用volatile修饰和不使用volatile的代码分别获取到class的汇编码,然后进行对比,你会发现标有volatile的变量在进行写操作时,会在前面加上lock质量前缀。而lock指令前缀会做如下两件事
- 현재 데이터 프로세서 캐시 라인이 메모리에 다시 기록된다. 신호의 임의의 공유 메모리 배타적있는 동안 명령들의 실행 동안 로크 명령 프리픽스는, 로크 신호를 생성한다 로크 신호는 다음을 보장한다. 버스 잠금 신호는 일반적으로 잠겨 있지만, 잠금 캐시되지 않습니다. 대형 버스 로크 오버 헤드 때문에.
- 데이터 캐시 라인은 주소가 유효하지 않습니다에 다른 CPU 캐시 데이터를 만들 것입니다 메모리 작업에 다시 기록됩니다.
휘발성 및 동기화의 차이
- 인스턴스 변수 또는 변형 만 휘발성 클래스 변수는 수정 또는 문 블록의 동기화 방법
- 원 자성을 보장 할 수 없습니다 휘발성, 원 자성을 보장하기 위해 동기화
- 휘발성 및 질서 보장하기 위해 동기화하지만, 구현은 동일하지 않습니다 수
- 반대로 동기화를 막힘 스레드를하지 않습니다 휘발성
개요
그는 효과적으로 순서와 가시성의 동시 프로그래밍을 달성 할 수 있었기 때문에 경량으로 알려져 휘발성 동기화 할 수 있습니다. 그러나 동시에 그것은 자성 문제를 보장하지 같은 자신의 단점이있다. 장면의 일부 스레드를 자극하고 폐쇄하는 등 직접 휘발성. 동기화 동시 프로그래밍은 조금 그 세 요소를 보장하지만, 스레드 차단 될 것이지만.