摘要:共享數(shù)據(jù)使線程之間的通信比進程之間的通信更有效。并發(fā)模型和的區(qū)別說明的作用是啟動一個新線程操作系統(tǒng)級別,有一個方法啟動新線程,新線程會執(zhí)行相應(yīng)的方法。多帶帶調(diào)用會在當(dāng)前線程中執(zhí)行并不會啟動新線程創(chuàng)建一個線程即可但是這個線程沒有執(zhí)行任何代碼段。
tutorials site
并發(fā)Concurrency發(fā)展的歷史單CPU,一次只能運行一個程序 -- 多任務(wù),一次同時運行多個任務(wù) (問題是每個任務(wù)不能永遠占有資源或者CPU,不再使用資源或者CPU的程序需要釋放掉自己的資源) -- 多線程,每個任務(wù)都有多線程進行處理,每個執(zhí)行著的線程都可以當(dāng)做是一個CPU。(問題是 每個線程都執(zhí)行相同的任務(wù),因此同時讀和寫同一段內(nèi)存,這會導(dǎo)致單線程不能出現(xiàn)的問題) 舉個例子: 如果一個線程讀了一塊內(nèi)存 同時發(fā)生了另一個線程寫到了這塊內(nèi)存。那么第一個線程讀到的是什么? old value or the value just wriiten or a value mid between the two. 如果更多的線程同時寫到了這個內(nèi)存,第一個線程讀到什么。 Therefore it is important as a developer to know how to take the right precautions - meaning learning to control how threads access shared resources like memory, files, databases etc. That is one of the topics this Java concurrency tutorial addresses.
多進程和多線程的區(qū)別?
本質(zhì)的區(qū)別在于每個進程擁有自己的一整套變量,而線程則共享數(shù)據(jù)。共享數(shù)據(jù)使線程之間的通信比進程之間的通信更有效。
此外在有些操作系統(tǒng)中,與進程相比較,線程更加輕量級,創(chuàng)建,撤銷一個線程比啟動線程開銷要小很多。
棧的組成JVM 的內(nèi)存模型 可以分為調(diào)用棧,堆,方法區(qū),寄存器,本地方法棧;其中主要組成是前二。
同一進程中的多條線程將共享該進程中的全部系統(tǒng)資源,如虛擬地址空間,文件描述符和信號處理等等。但同一進程中的多個線程有各自的調(diào)用棧(call stack),自己的寄存器環(huán)境(register context),自己的線程本地存儲(thread-local storage)
每一個在JVM中運行的線程都有自己的調(diào)用棧call stack, 調(diào)用棧存儲著該線程調(diào)用了哪些方法以及這些方法的局部變量。每個棧只能查看自己的局部變量,無法查看其它棧的局部變量。
Objects on the heap can be accessed by all threads that have a reference to the object. When a thread has access to an object, it can also get access to that object"s member variables. If two threads call a method on the same object at the same time, they will both have access to the object"s member variables, but each thread will have its own copy of the local variables.
使用并發(fā)的好處:
* 更好的資源利用率 * 更精簡的程序設(shè)計(一個線程負(fù)責(zé)讀,一個線程負(fù)責(zé)寫,一個線程只做一個功能,這樣程序設(shè)計精簡多了) * 更多響應(yīng)的程序 (服務(wù)器監(jiān)聽線程,處理線程的例子)
使用并發(fā)的代價:
* 設(shè)計更復(fù)雜 Code executed by multiple threads accessing shared data need special attention. Thread interaction is far from always simple. Errors arising from incorrect thread synchronization can be very hard to detect, reproduce and fix. * 上下文切換 When a CPU switches from executing one thread to executing another, the CPU needs to save the local data, program pointer etc. of the current thread, and load the local data, program pointer etc. of the next thread to execute. This switch is called a "context switch". * 消耗資源 CPU需要額外的空間時間去維護一個線程。
并發(fā)模型
Creating and Starting java threadsstart 和 run的區(qū)別說明
* start() 的作用是 啟動一個新線程(操作系統(tǒng)級別,有一個native方法start0() 啟動新線程),新線程會執(zhí)行相應(yīng)的run方法。 * run() 和普通的成員方法一樣,可以被重復(fù)調(diào)用。 多帶帶調(diào)用run() 會在當(dāng)前線程中執(zhí)行run() 并不會啟動新線程
創(chuàng)建一個線程Thread thread = new Thread(); thread.start() 即可
但是這個線程沒有執(zhí)行任何代碼段。
有兩種方式可以指定哪段代碼 一個線程會執(zhí)行。
繼承Thread - Thread Subclass
java public class MyThread extends Thread { public void run(){ System.out.println("MyThread running"); } }
To create and start the above thread you can do like this:
java MyThread myThread = new MyThread(); myTread.start();
覆蓋run方法 - Runnable Interface Implemention
第二種方式指定線程應(yīng)該運行那端代碼 是創(chuàng)建一個類執(zhí)行java.lang.Runnable接口
public class MyRunnable implements Runnable { public void run(){ System.out.println("MyRunnable running"); } }
To have the run() method executed by a thread, pass an instance of MyRunnable to a Thread in its constructor. Here is how that is done:
Thread thread = new Thread(new MyRunnable()); thread.start();Race Conditions and Critical Sections
The problems arise when multiple threads access the same resources.For instance the same memory (variables, arrays, or objects), systems (databases, web services etc.) or files. In fact, problems only arise if one or more of the threads write to these resources. It is safe to let multiple threads read the same resources, as long as the resources do not change.
Thread Safety and Shared ResourcesThe situation where two threads compete for the same resource, where the sequence in which the resource is accessed is significant, is called race conditions. A code section that leads to race conditions is called a critical section. In the previous example the method add() is a critical section, leading to race conditions. Race conditions can be avoided by proper thread synchronization in critical sections.
Code that is safe to call by multiple threads simultanously is called thread safe. If a piece of code is thread safe, then it contains no race conditions. Race condition only occur when multiple threads update shared resources. Therefore it is important to know what resources Java threads share when executing.
Java 不共享的資源有:
局部變量 Local varables
局部變量(方法內(nèi)部變量)存儲在每個線程自己的棧里面,這意味著局部變量不會被多個線程共享。這也意味著所有局部變量都是線程安全的thread safe.
比如:
public void someMethod(){ long threadSafeInt = 0; threadSafeInt++; }
Java 共享的資源有:
局部對象引用 Local Object References
引用本身是線程安全的,因為他的局部變量。但是引用所?指的對象object并非存儲在線程的局部棧的,而是存儲在共享堆里 shared heap。 每個線程在各自的方法內(nèi)創(chuàng)建的局部對象,只要不作為返回值返回,其他線程訪問不到,不產(chǎn)生競爭就不會有安全問題
比如如下的例子,因為localObject沒有作為返回值返回,其他的線程獲取不到這個對象的
javapublic void someMethod(){ LocalObject localObject = new LocalObject(); localObject.callMethod(); method2(localObject); } public void method2(LocalObject localObject){ localObject.setValue("value"); }
對象成員變量
對象成員與對象一起存儲在堆里面,對象成員是屬于類的,局部對象引用是屬于方法的,不同的線程訪問或者修改一個類的成員時就會存在競爭.
比如這個例子中,方法add就是線程不安全的(因為build是對象成員變量,多線程都對它同時操作)。
public class NotThreadSafe{ StringBuilder builder = new StringBuilder(); public add(String text){ this.builder.append(text); } }
如果兩個線程同時調(diào)用同一個 NotThreadSafe 實例的 add() 方法就會引起race condition。比如:
NotThreadSafe sharedInstance = new NotThreadSafe(); new Thread(new MyRunnable(sharedInstance)).start(); // 線程1 new Thread(new MyRunnable(sharedInstance)).start(); // 線程2 public class MyRunnable implements Runnable{ NotThreadSafe instance = null; public MyRunnable(NotThreadSafe instance){ this.instance = instance; } public void run(){ this.instance.add("some text"); } }
然而如果兩個線程在不同的實例上面同時調(diào)用 add() 方法并不會引起靜態(tài)條件。下面是稍微修改之后的例子:
new Thread(new MyRunnable(new NotThreadSafe())).start(); new Thread(new MyRunnable(new NotThreadSafe())).start();
現(xiàn)在這兩個線程都有自己的 NotThreadSafe 實例,所以它們對 add 方法的調(diào)用并不會妨礙對方,這段代碼沒有競態(tài)條件。所以即使一個對象不是線程安全的,仍可以找到一個方式來消除競態(tài)條件?!?br> 可以使用線程逃逸準(zhǔn)則 Thread Control Escape Rule 來判斷是否代碼訪問的資源是線程安全的。
如果一個資源在一個線程的控制下被創(chuàng)建、使用和銷毀并且永遠不會逃脫線程的控制,則該資源的使用是線程安全的。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/65302.html
摘要:請參看前一篇文章并發(fā)學(xué)習(xí)筆記一原子性可見性有序性問題六等待通知機制什么是等待通知機制當(dāng)線程不滿足某個條件,則進入等待狀態(tài)如果線程滿足要求的某個條件后,則通知等待的線程重新執(zhí)行。經(jīng)極客時間并發(fā)編程實戰(zhàn)專欄內(nèi)容學(xué)習(xí)整理 請參看前一篇文章:Java 并發(fā)學(xué)習(xí)筆記(一)——原子性、可見性、有序性問題 六、等待—通知機制 什么是等待通知—機制?當(dāng)線程不滿足某個條件,則進入等待狀態(tài);如果線程滿足要...
摘要:最后,總結(jié)一下,導(dǎo)致并發(fā)問題的三個源頭分別是原子性一個線程在執(zhí)行的過程當(dāng)中不被中斷??梢娦砸粋€線程修改了共享變量,另一個線程能夠馬上看到,就叫做可見性。 計算機的 CPU、內(nèi)存、I/O 設(shè)備的速度一直存在較大的差異,依次是 CPU > 內(nèi)存 > I/O 設(shè)備,為了權(quán)衡這三者的速度差異,主要提出了三種解決辦法: CPU 增加了緩存,均衡和內(nèi)存的速度差異 發(fā)明了進程、線程,分時復(fù)用 CP...
摘要:不剝奪條件進程已獲得的資源,在末使用完之前,不能強行剝奪。如果能確保所有的線程都是按照相同的順序獲得鎖,那么死鎖就不會發(fā)生。按照順序加鎖是一種有效的死鎖預(yù)防機制。這種機制存在一個問題,在中不能對同步塊設(shè)置超時時間。 [tutorial site][1] 死鎖 deadlock 死鎖是指兩個或兩個以上的進程在執(zhí)行過程中,因競爭資源而造成的一種互相等待的現(xiàn)在,若無外力作用,它們都無法推...
摘要:每個通過網(wǎng)絡(luò)到達服務(wù)器的連接都被包裝成一個任務(wù)并且傳遞給線程池。線程池的線程會并發(fā)的處理連接上的請求。用線程池控制線程數(shù)量,其他線程排隊等候。實現(xiàn)包,線程池頂級接口是但是嚴(yán)格意義講并不是一個線程。此線程池支持定時以及周期性執(zhí)行任務(wù)的需求。 tutorial site1tutorial site2 一個問題: 每啟動一個新線程都會有相應(yīng)的性能開銷(涉及到OS的交互:創(chuàng)建線程,銷毀線程...
摘要:除此之外,把并發(fā)安全字典封裝在一個結(jié)構(gòu)體類型中,往往是一個很好的選擇。請看下面的代碼如上所示,我編寫了一個名為的結(jié)構(gòu)體類型,它代表了鍵類型為值類型為的并發(fā)安全字典。在這個結(jié)構(gòu)體類型中,只有一個類型的字段。34 | 并發(fā)安全字典sync.Map (上)我們今天再來講一個并發(fā)安全的高級數(shù)據(jù)結(jié)構(gòu):sync.Map。眾所周知,Go 語言自帶的字典類型map并不是并發(fā)安全的。前導(dǎo)知識:并發(fā)安全字典誕生...
閱讀 2569·2021-11-23 09:51
閱讀 2481·2021-09-30 09:48
閱讀 1076·2021-09-10 10:51
閱讀 2213·2021-08-12 13:22
閱讀 3568·2021-08-11 10:24
閱讀 2166·2019-08-30 15:55
閱讀 646·2019-08-30 14:05
閱讀 3211·2019-08-30 13:03