午夜剧场伦理_日本一道高清_国产又黄又硬_91黄色网战_女同久久另类69精品国产_妹妹的朋友在线

您的位置:首頁技術(shù)文章
文章詳情頁

Java線程內(nèi)存模型,線程、工作內(nèi)存、主內(nèi)存

瀏覽:203日期:2022-09-05 14:32:09
java線程內(nèi)存模型

線程、工作內(nèi)存、主內(nèi)存三者之間的交互關(guān)系圖:

Java線程內(nèi)存模型,線程、工作內(nèi)存、主內(nèi)存

key edeas

所有線程共享主內(nèi)存,每個(gè)線程有自己的工作內(nèi)存

refreshing local memory to/from main memory must comply to JMM rules

產(chǎn)生線程安全的原因

線程的working memory是cpu的寄存器和高速緩存的抽象描述:現(xiàn)在的計(jì)算機(jī),cpu在計(jì)算的時(shí)候,并不總是從內(nèi)存讀取數(shù)據(jù),它的數(shù)據(jù)讀取順序優(yōu)先級(jí) 是: 寄存器-高速緩存-內(nèi)存 。線程耗費(fèi)的是CPU,線程計(jì)算的時(shí)候,原始的數(shù)據(jù)來自內(nèi)存,在計(jì)算過程中,有些數(shù)據(jù)可能被頻繁讀取,這些數(shù)據(jù)被存儲(chǔ)在寄存器和高速緩存中,當(dāng)線程計(jì)算完后,這些緩存的數(shù)據(jù)在適當(dāng)?shù)臅r(shí)候應(yīng)該寫回內(nèi)存。當(dāng)多個(gè)線程同時(shí)讀寫某個(gè)內(nèi)存數(shù)據(jù)時(shí),就會(huì)產(chǎn)生多線程并發(fā)問題,涉及到三個(gè)特 性:原子性,有序性,可見性。 支持多線程的平臺(tái)都會(huì)面臨 這種問題,運(yùn)行在多線程平臺(tái)上支持多線程的語言應(yīng)該提供解決該問題的方案。

JVM是一個(gè)虛擬的計(jì)算機(jī),它也會(huì)面臨多線程并發(fā)問題,java程序運(yùn)行在java虛擬機(jī)平臺(tái)上,java程序員不可能直接去控制底層線程對(duì)寄存器高速緩存內(nèi)存之間的同步,那么java從語法層面,應(yīng)該給開發(fā)人員提供一種解決方案,這個(gè)方案就是諸如 synchronized, volatile,鎖機(jī)制(如同步塊,就緒隊(duì) 列,阻塞隊(duì)列)等等。這些方案只是語法層面的,但我們要從本質(zhì)上去理解它;

每個(gè)線程都有自己的執(zhí)行空間(即工作內(nèi)存),線程執(zhí)行的時(shí)候用到某變量,首先要將變量從主內(nèi)存拷貝的自己的工作內(nèi)存空間,然后對(duì)變量進(jìn)行操作:讀取,修改,賦值等,這些均在工作內(nèi)存完成,操作完成后再將變量寫回主內(nèi)存;

各個(gè)線程都從主內(nèi)存中獲取數(shù)據(jù),線程之間數(shù)據(jù)是不可見的;打個(gè)比方:主內(nèi)存變量A原始值為1,線程1從主內(nèi)存取出變量A,修改A的值為2,在線程1未將變量A寫回主內(nèi)存的時(shí)候,線程2拿到變量A的值仍然為1;

這便引出“可見性”的概念:當(dāng)一個(gè)共享變量在多個(gè)線程的工作內(nèi)存中都有副本時(shí),如果一個(gè)線程修改了這個(gè)共享變量的副本值,那么其他線程應(yīng)該能夠看到這個(gè)被修改后的值,這就是多線程的可見性問題。

普通變量情況:如線程A修改了一個(gè)普通變量的值,然后向主內(nèi)存進(jìn)行寫回,另外一條線程B在線程A回寫完成了之后再從主內(nèi)存進(jìn)行讀取操作,新變量的值才會(huì)對(duì)線程B可見;

如何保證線程安全

編寫線程安全的代碼,本質(zhì)上就是管理對(duì)狀態(tài)(state)的訪問,而且通常都是共享的、可變的狀態(tài)。這里的狀態(tài)就是對(duì)象的變量(靜態(tài)變量和實(shí)例變量)

線程安全的前提是該變量是否被多個(gè)線程訪問, 保證對(duì)象的線程安全性需要使用同步來協(xié)調(diào)對(duì)其可變狀態(tài)的訪問;若是做不到這一點(diǎn),就會(huì)導(dǎo)致臟數(shù)據(jù)和其他不可預(yù)期的后果。無論何時(shí),只要有多于一個(gè)的線程訪問給定的狀態(tài)變量,而且其中某個(gè)線程會(huì)寫入該變量,此時(shí)必須使用同步來協(xié)調(diào)線程對(duì)該變量的訪問。Java中首要的同步機(jī)制是synchronized關(guān)鍵字,它提供了獨(dú)占鎖。除此之外,術(shù)語“同步”還包括volatile變量,顯示鎖和原子變量的使用。

在沒有正確同步的情況下,如果多個(gè)線程訪問了同一個(gè)變量,你的程序就存在隱患。有3種方法修復(fù)它:

l 不要跨線程共享變量;

l 使?fàn)顟B(tài)變量為不可變的;或者

l 在任何訪問狀態(tài)變量的時(shí)候使用同步。

volatile要求程序?qū)ψ兞康拿看涡薷?,都寫回主?nèi)存,這樣便對(duì)其它線程課件,解決了可見性的問題,但是不能保證數(shù)據(jù)的一致性;特別注意:原子操作:根據(jù)Java規(guī)范,對(duì)于基本類型的賦值或者返回值操作,是原子操作。但這里的基本數(shù)據(jù)類型不包括long和double, 因?yàn)镴VM看到的基本存儲(chǔ)單位是32位,而long 和double都要用64位來表示。所以無法在一個(gè)時(shí)鐘周期內(nèi)完成

通俗的講一個(gè)對(duì)象的狀態(tài)就是它的數(shù)據(jù),存儲(chǔ)在狀態(tài)變量中,比如實(shí)例域或者靜態(tài)域;無論何時(shí),只要多于一個(gè)的線程訪問給定的狀態(tài)變量。而且其中某個(gè)線程會(huì)寫入該變量,此時(shí)必須使用同步來協(xié)調(diào)線程對(duì)該變量的訪問;

同步鎖:每個(gè)JAVA對(duì)象都有且只有一個(gè)同步鎖,在任何時(shí)刻,最多只允許一個(gè)線程擁有這把鎖。

當(dāng)一個(gè)線程試圖訪問帶有synchronized(this)標(biāo)記的代碼塊時(shí),必須獲得 this關(guān)鍵字引用的對(duì)象的鎖,在以下的兩種情況下,本線程有著不同的命運(yùn)。

1、 假如這個(gè)鎖已經(jīng)被其它的線程占用,JVM就會(huì)把這個(gè)線程放到本對(duì)象的鎖池中。本線程進(jìn)入阻塞狀態(tài)。鎖池中可能有很多的線程,等到其他的線程釋放了鎖,JVM就會(huì)從鎖池中隨機(jī)取出一個(gè)線程,使這個(gè)線程擁有鎖,并且轉(zhuǎn)到就緒狀態(tài)。

2、 假如這個(gè)鎖沒有被其他線程占用,本線程會(huì)獲得這把鎖,開始執(zhí)行同步代碼塊。

(一般情況下在執(zhí)行同步代碼塊時(shí)不會(huì)釋放同步鎖,但也有特殊情況會(huì)釋放對(duì)象鎖

如在執(zhí)行同步代碼塊時(shí),遇到異常而導(dǎo)致線程終止,鎖會(huì)被釋放;在執(zhí)行代碼塊時(shí),執(zhí)行了鎖所屬對(duì)象的wait()方法,這個(gè)線程會(huì)釋放對(duì)象鎖,進(jìn)入對(duì)象的等待池中)

Synchronized關(guān)鍵字保證了數(shù)據(jù)讀寫一致和可見性等問題,但是他是一種阻塞的線程控制方法,在關(guān)鍵字使用期間,所有其他線程不能使用此變量,這就引出了一種叫做非阻塞同步的控制線程安全的需求;

ThreadLocal 解析

顧名思義它是local variable(線程局部變量)。它的功用非常簡單,就是為每一個(gè)使用該變量的線程都提供一個(gè)變量值的副本,是每一個(gè)線程都可以獨(dú)立地改變自己的副本,而不會(huì)和其它線程的副本沖突。從線程的角度看,就好像每一個(gè)線程都完全擁有該變量。

每個(gè)線程都保持對(duì)其線程局部變量副本的隱式引用,只要線程是活動(dòng)的并且 ThreadLocal 實(shí)例是可訪問的;在線程消失之后,其線程局部實(shí)例的所有副本都會(huì)被垃圾回收(除非存在對(duì)這些副本的其他引用)。

Object wait()和notify()方法解析

Object的wait()和notify()、notifyAll()方法,使用一個(gè)對(duì)象作為鎖,然后調(diào)用wait()就會(huì)掛起當(dāng)前線程,同時(shí)釋放對(duì)象鎖;

notify()使用要首先獲取對(duì)象鎖,然后才能喚醒被掛起的線程(因?yàn)榈却龑?duì)象鎖而掛起的)

notifyAll():喚醒在此對(duì)象監(jiān)視器上等待的所有線程。

wait()在其他線程調(diào)用此對(duì)象的 notify() 方法或 notifyAll() 方法前,導(dǎo)致當(dāng)前線程等待。

拋出: IllegalMonitorStateException - 如果當(dāng)前線程不是此對(duì)象監(jiān)視器的所有者

package com.taobao.concurrency;public class WaitTest { public static String a = '';// 作為監(jiān)視器對(duì)象 public static void main(String[] args) throws InterruptedException {WaitTest wa = new WaitTest();TestTask task = wa.new TestTask();Thread t = new Thread(task);t.start();Thread.sleep(12000);for (int i = 5; i > 0; i--) { System.out.println('快喚醒掛起的線程************'); Thread.sleep(1000);}System.out.println('收到,馬上!喚醒掛起的線程************');synchronized (a) { a.notifyAll();} } class TestTask implements Runnable {@Overridepublic void run() { synchronized (a) {try { for (int i = 10; i > 0; i--) {Thread.sleep(1000);System.out.println('我在運(yùn)行 ***************'); } a.wait(); for (int i = 10; i > 0; i--) {System.out.println('謝謝喚醒**********又開始運(yùn)行了*******'); }} catch (InterruptedException e) { e.printStackTrace();} }} }}

用wait notify 解決生產(chǎn)者消費(fèi)者問題代碼:

package com.taobao.concurrency;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit;class Meal { private final int orderNum; public Meal(int orderNum) {this.orderNum = orderNum; } public String toString() {return 'Meal ' + orderNum; }}class WaitPerson implements Runnable { private Restaurant restaurant; public WaitPerson(Restaurant r) {this.restaurant = r; } @Override public void run() {try { while (!Thread.interrupted()) {synchronized (this) { while (restaurant.meal == null)wait();// ..for the chef to produce a meal}System.out.println('WaitPerson got' + restaurant.meal);synchronized (restaurant.chef) { restaurant.meal = null; restaurant.chef.notifyAll();// ready for another} } TimeUnit.MICROSECONDS.sleep(100);} catch (InterruptedException e) { System.out.println('WaitPerson interrupted');} }}class Chef implements Runnable { private Restaurant restaurant; private int count = 0; public Chef(Restaurant r) {this.restaurant = r; } @Override public void run() {try { while (!Thread.interrupted()) {synchronized (this) { while (restaurant.meal != null)wait();// ...for the meal to be taken}if (++count == 10) { System.out.println('Out of food,closing'); restaurant.exec.shutdownNow();}System.out.println('Order up!');synchronized (restaurant.waitPerson) { restaurant.meal = new Meal(count); restaurant.waitPerson.notifyAll();} }} catch (InterruptedException e) {} }}public class Restaurant { Meal meal; ExecutorService exec = Executors.newCachedThreadPool(); WaitPerson waitPerson = new WaitPerson(this); Chef chef = new Chef(this); public Restaurant() {exec.execute(chef);exec.execute(waitPerson); } public static void main(String[] args) {new Restaurant(); }}

用ArrayBlockingQueue解決生產(chǎn)者消費(fèi)者問題 ;默認(rèn)使用的是非公平鎖

take():取走BlockingQueue里排在首位的對(duì)象,若BlockingQueue為空,阻斷進(jìn)入等待狀態(tài)直到Blocking有新的對(duì)象被加入為止,若請(qǐng)求不到此線程被加入阻塞隊(duì)列;

如果使用公平鎖,當(dāng)有內(nèi)容可以消費(fèi)時(shí),會(huì)從隊(duì)首取出消費(fèi)者線程進(jìn)行消費(fèi)(即等待時(shí)間最長的線程)

add(anObject):把a(bǔ)nObject加到BlockingQueue里,即如果BlockingQueue可以容納,則返回true,否則招聘異常

package com.taobao.concurrency;import java.util.concurrent.ArrayBlockingQueue;import java.util.concurrent.BlockingQueue;public class TestBlockingQueues { public static void main(String[] args) {BlockingQueue<String> queue = new ArrayBlockingQueue<String>(20);Thread pro = new Thread(new Producer(queue), '生產(chǎn)者');pro.start();for (int i = 0; i < 10; i++) { Thread t = new Thread(new Concumer(queue), '消費(fèi)者 ' + i); t.start();} }}class Producer implements Runnable { BlockingQueue<String> queue; public Producer(BlockingQueue<String> queue) {this.queue = queue; } @Override public void run() {int i = 0;while (true) { try {System.out.println('生產(chǎn)者生產(chǎn)食物, 食物編號(hào)為:' + i);queue.put(' 食物 ' + i++);Thread.sleep(1000); } catch (InterruptedException e) {System.out.println('生產(chǎn)者被中斷'); }} }}class Concumer implements Runnable { BlockingQueue<String> queue; public Concumer(BlockingQueue<String> queue) {this.queue = queue; } @Override public void run() {while (true) { try {System.out.println(Thread.currentThread().getName() + '消費(fèi):'+ queue.take()); } catch (InterruptedException e) {System.out.println('消費(fèi)者被中斷'); }} }}執(zhí)行結(jié)果:消費(fèi)者 0 請(qǐng)求消費(fèi)消費(fèi)者 2 請(qǐng)求消費(fèi)消費(fèi)者 4 請(qǐng)求消費(fèi)消費(fèi)者 6 請(qǐng)求消費(fèi)消費(fèi)者 8 請(qǐng)求消費(fèi)消費(fèi)者 5 請(qǐng)求消費(fèi)生產(chǎn)者生產(chǎn)食物, 食物編號(hào)為:0消費(fèi)者 0消費(fèi): 食物 0消費(fèi)者 1 請(qǐng)求消費(fèi)消費(fèi)者 3 請(qǐng)求消費(fèi)消費(fèi)者 7 請(qǐng)求消費(fèi)消費(fèi)者 9 請(qǐng)求消費(fèi)消費(fèi)者 0 請(qǐng)求消費(fèi)生產(chǎn)者生產(chǎn)食物, 食物編號(hào)為:1消費(fèi)者 2消費(fèi): 食物 1消費(fèi)者 2 請(qǐng)求消費(fèi)生產(chǎn)者生產(chǎn)食物, 食物編號(hào)為:2消費(fèi)者 4消費(fèi): 食物 2消費(fèi)者 4 請(qǐng)求消費(fèi)生產(chǎn)者生產(chǎn)食物, 食物編號(hào)為:3消費(fèi)者 6消費(fèi): 食物 3消費(fèi)者 6 請(qǐng)求消費(fèi)生產(chǎn)者生產(chǎn)食物, 食物編號(hào)為:4消費(fèi)者 8消費(fèi): 食物 4消費(fèi)者 8 請(qǐng)求消費(fèi)生產(chǎn)者生產(chǎn)食物, 食物編號(hào)為:5消費(fèi)者 5消費(fèi): 食物 5消費(fèi)者 5 請(qǐng)求消費(fèi)生產(chǎn)者生產(chǎn)食物, 食物編號(hào)為:6消費(fèi)者 1消費(fèi): 食物 6消費(fèi)者 1 請(qǐng)求消費(fèi)生產(chǎn)者生產(chǎn)食物, 食物編號(hào)為:7消費(fèi)者 3消費(fèi): 食物 7消費(fèi)者 3 請(qǐng)求消費(fèi)生產(chǎn)者生產(chǎn)食物, 食物編號(hào)為:8消費(fèi)者 7消費(fèi): 食物 8消費(fèi)者 7 請(qǐng)求消費(fèi)生產(chǎn)者生產(chǎn)食物, 食物編號(hào)為:9消費(fèi)者 9消費(fèi): 食物 9消費(fèi)者 9 請(qǐng)求消費(fèi)

多個(gè)生產(chǎn)者,多個(gè)消費(fèi)者

package com.taobao.concurrency;import java.util.concurrent.ArrayBlockingQueue;import java.util.concurrent.BlockingQueue;public class TestBlockingQueues { public static void main(String[] args) {BlockingQueue<String> queue = new ArrayBlockingQueue<String>(20);for (int i = 0; i < 10; i++) { Thread pro = new Thread(new Producer(queue), '生產(chǎn)者' + i); pro.start();}for (int i = 0; i < 10; i++) { Thread t = new Thread(new Concumer(queue), '消費(fèi)者 ' + i); t.start();} }}class Producer implements Runnable { BlockingQueue<String> queue; public Producer(BlockingQueue<String> queue) {this.queue = queue; } @Override public void run() {int i = 0;while (true) { try { System.out.println(Thread.currentThread().getName() + '生產(chǎn)食物, 食物編號(hào)為:' + Thread.currentThread().getName() + i); queue.put(' 食物 ' + Thread.currentThread().getName() + i++); Thread.sleep(10000); } catch (InterruptedException e) {System.out.println('生產(chǎn)者被中斷'); }} }}class Concumer implements Runnable { BlockingQueue<String> queue; public Concumer(BlockingQueue<String> queue) {this.queue = queue; } @Override public void run() {while (true) { System.out.println(Thread.currentThread().getName() + ' 請(qǐng)求消費(fèi)'); try {System.out.println(Thread.currentThread().getName() + '消費(fèi):'+ queue.take());Thread.sleep(100); } catch (InterruptedException e) {System.out.println('消費(fèi)者被中斷'); }} }}生產(chǎn)者0生產(chǎn)食物, 食物編號(hào)為:生產(chǎn)者00生產(chǎn)者2生產(chǎn)食物, 食物編號(hào)為:生產(chǎn)者20生產(chǎn)者1生產(chǎn)食物, 食物編號(hào)為:生產(chǎn)者10生產(chǎn)者3生產(chǎn)食物, 食物編號(hào)為:生產(chǎn)者30生產(chǎn)者4生產(chǎn)食物, 食物編號(hào)為:生產(chǎn)者40生產(chǎn)者6生產(chǎn)食物, 食物編號(hào)為:生產(chǎn)者60生產(chǎn)者8生產(chǎn)食物, 食物編號(hào)為:生產(chǎn)者80生產(chǎn)者5生產(chǎn)食物, 食物編號(hào)為:生產(chǎn)者50生產(chǎn)者7生產(chǎn)食物, 食物編號(hào)為:生產(chǎn)者70生產(chǎn)者9生產(chǎn)食物, 食物編號(hào)為:生產(chǎn)者90消費(fèi)者 0 請(qǐng)求消費(fèi)消費(fèi)者 0消費(fèi): 食物 生產(chǎn)者00消費(fèi)者 2 請(qǐng)求消費(fèi)消費(fèi)者 2消費(fèi): 食物 生產(chǎn)者20消費(fèi)者 1 請(qǐng)求消費(fèi)消費(fèi)者 1消費(fèi): 食物 生產(chǎn)者10消費(fèi)者 4 請(qǐng)求消費(fèi)消費(fèi)者 4消費(fèi): 食物 生產(chǎn)者30消費(fèi)者 3 請(qǐng)求消費(fèi)消費(fèi)者 6 請(qǐng)求消費(fèi)消費(fèi)者 6消費(fèi): 食物 生產(chǎn)者40消費(fèi)者 3消費(fèi): 食物 生產(chǎn)者60消費(fèi)者 8 請(qǐng)求消費(fèi)消費(fèi)者 8消費(fèi): 食物 生產(chǎn)者80消費(fèi)者 5 請(qǐng)求消費(fèi)消費(fèi)者 5消費(fèi): 食物 生產(chǎn)者50消費(fèi)者 7 請(qǐng)求消費(fèi)消費(fèi)者 7消費(fèi): 食物 生產(chǎn)者70消費(fèi)者 9 請(qǐng)求消費(fèi)消費(fèi)者 9消費(fèi): 食物 生產(chǎn)者90消費(fèi)者 0 請(qǐng)求消費(fèi)消費(fèi)者 1 請(qǐng)求消費(fèi)消費(fèi)者 2 請(qǐng)求消費(fèi)消費(fèi)者 4 請(qǐng)求消費(fèi)消費(fèi)者 3 請(qǐng)求消費(fèi)消費(fèi)者 5 請(qǐng)求消費(fèi)消費(fèi)者 7 請(qǐng)求消費(fèi)消費(fèi)者 9 請(qǐng)求消費(fèi)消費(fèi)者 6 請(qǐng)求消費(fèi)消費(fèi)者 8 請(qǐng)求消費(fèi)生產(chǎn)者0生產(chǎn)食物, 食物編號(hào)為:生產(chǎn)者01消費(fèi)者 0消費(fèi): 食物 生產(chǎn)者01生產(chǎn)者2生產(chǎn)食物, 食物編號(hào)為:生產(chǎn)者21生產(chǎn)者4生產(chǎn)食物, 食物編號(hào)為:生產(chǎn)者41消費(fèi)者 1消費(fèi): 食物 生產(chǎn)者21生產(chǎn)者1生產(chǎn)食物, 食物編號(hào)為:生產(chǎn)者11消費(fèi)者 2消費(fèi): 食物 生產(chǎn)者41消費(fèi)者 4消費(fèi): 食物 生產(chǎn)者11生產(chǎn)者3生產(chǎn)食物, 食物編號(hào)為:生產(chǎn)者31

條件隊(duì)列解釋:

Condition queuesare like the 'toast is ready' bell on your toaster. If you are listening for it, you are notified promptly when your toast is ready and can drop what you are doing (or not, maybe you want to finish the newspaper first) and get your toast. If you are not listening for it (perhaps you went outside to get the newspaper), you could miss the notification, but on return to the kitchen you can observe the state of the toaster and either retrieve the toast if it is finished or start listening for the bell again if it is not.

基于條件的:多線程情況下,某個(gè)條件在某個(gè)時(shí)刻為假,不代表一直為假,可能到某個(gè)時(shí)刻就好了!

Lock 使用的默認(rèn) 為非公平鎖;condition對(duì)象繼承了與之相關(guān)的鎖的共平性特性,如果是公平的鎖,線程會(huì)依照FIFO的順序從Condition.wait中被釋放;ArrayBlockingQueue中有一個(gè)比較不好的地方,生產(chǎn)者每次生產(chǎn)完之后,都要通知消費(fèi)者,至于有沒有性能損失TODO

來自:https://zhuanlan.zhihu.com/p/25474331

標(biāo)簽: Java
主站蜘蛛池模板: 青娱乐av | 国产美女精品 | 99re视频这里只有精品 | 日本网站黄色 | 色婷婷狠狠干 | 天天干天天色综合 | 精品国产乱码久久久久久久 | 成人手机av | 久久欧洲 | 中国毛片直接看 | 久久在线播放 | 久久视频免费 | 成人免费公开视频 | 欧美激情18p | 大陆一级片 | 黄色av播放 | 久久午夜鲁丝片 | 综合自拍 | 久久视频在线 | 福利在线看 | 色婷婷亚洲 | 国产三级理论 | 久久精品操 | 热久久网站 | 国产毛片在线 | 日韩国产中文字幕 | 久久夫妻视频 | 精品一区二区三区四区五区六区 | 人人草在线观看 | 天天狠天天操 | 四虎网址在线观看 | 日本新japanese乱熟 | 成人高清在线 | 战狼4免费播放观看在线视频 | 亚洲精选一区二区三区 | 欧美在线色| 亚洲最大激情网 | 青青草av | 在线小视频你懂的 | 亚洲成av | 中文字幕1区2区 |