操做系統能夠多任務執行,每一個任務就是就是一個進程。
每一個任務(進程)能夠分多工做流分別執行。html
比較:進程:有獨立的代碼和數據空間(進程上下文),進程切換開銷大,進程是資源分配的最小單位。java
線程:每一個線程有獨立的運行棧和程序計數器(PC),線程切換開銷小。線程是cpu調度的最小單位。算法
並行與併發:緩存
進程和線程的生命週期:建立、就緒、運行、阻塞、終止安全
1)wait,notify和notifyAll只能在同步控制方法或者同步控制塊裏面使用,而sleep能夠在任何地方使用
2) sleep必須捕獲異常,而wait,notify和notifyAll不須要捕獲異常。sleep()睡眠時,保持對象鎖,仍然佔有該鎖;而wait()睡眠時,釋放對象鎖。
3)wait、sleep和join均可以用interrupt()打斷,若是此刻線程B正在wait/sleep /join,則線程B會馬上拋出InterruptedException,在catch() {} 中直接return便可安全地結束線程。多線程
Java線程的實現是基於一對一的線程模型,所謂的一對一模型,實際上就是經過語言級別層面程序去間接調用系統內核的線程模型,即咱們在使用Java線程時,Java虛擬機內部是轉而調用當前操做系統的內核線程來完成當前任務。併發
因爲咱們編寫的多線程程序屬於語言層面的,程序通常不會直接去調用內核線程,取而代之的是一種輕量級的進程(Light Weight Process),也是一般意義上的線程,因爲每一個輕量級進程都會映射到一個內核線程,所以咱們能夠經過輕量級進程調用內核線程,進而由操做系統內核將任務映射到各個處理器,這種輕量級進程與內核線程間1對1的關係就稱爲一對一的線程模型。ide
每一個線程最終都會映射到CPU中進行處理,若是CPU存在多核,那麼一個CPU將能夠並行執行多個線程任務。性能
建立多線程的方式:ui
1)繼承Thread類:new myThread(「A線程」).start();
2)實現Runnable接口:new Thread(new myThread("A線程")).start();
3)實現Callable接口
前面說了,線程是cpu的最新調度單位,即cup在執行一個任務(進程)時,是執行的進程中的更小粒度線程。
執行方式:1)(建立)線程對象。即爲該線程分配內存並初始化,其中一個工做就是拷貝主存中的共享變量到線程工做內存(拷貝時:對於基本類型,直接拷貝值;對於引用類型,拷貝引用變量,其值仍保存堆中);
2)線程調用start()方法(就緒)。
3)線程獲取到cpu時間片後,恢復cpu(運行)現場。即將線程的相關數據寫入cpu緩存,再到cpu寄存器等進行執行。
4)(結束)將在cpu中處理後的數據刷新到主存。而後空出的cpu繼續加載其餘線程的數據進行執行。
public class MyThread extends Thread{ int a=1;//多線程中的共享數據(基本數據類型),運行時直接拷貝值到線程工做內存 String str;//多線程中的共享數據(引用類型),運行時拷貝引用變量到線程工做內存 MyThrad(String str){this.str = str;} @Override public void run(){ str=str+a; } public static void main(String[] args){ String str=new String("hgp"); //啓動線程後會拷貝共享變量到各自線程的工做內存,處理完了再分別刷新到主存(就是上面堆內存中的str對象中) new Mythread(str).start(); new Mythread(str).start(); } }
不論是什麼內存模型,最終仍是運行在計算機硬件上的。當一個CPU須要訪問主存時,會先讀取一部分主存數據到CPU緩存,進而在讀取CPU緩存到寄存器。當CPU須要寫數據到主存時,一樣會先flush寄存器到CPU緩存,而後再在某些節點把緩存數據flush到主存。
前提:上面說了對於線程的執行,並非直接進行的,主存共享變量的操做要通過讀入線程內存、cpu緩存等,待數據在cpu中執行完了再通過緩存、線程內存寫入主存。也就是說線程的執行有一個時間過程,在這個過程當中多線程對同一代碼塊的執行是彼此獨立的,由於cpu操做的操做數已是主存數據的拷貝了。
1)這樣的話如果非原子性操做就易出現錯誤,解決方法——線程同步,經過對象鎖機制實現,用關鍵字synchronized聲明。
synchronized關鍵字的鎖機制,鎖的是對象:
當synchronized使用在方法上或成員變量上,鎖的是該實例對象;
當synchronized使用在static靜態成員上,鎖的是該類型的Class對象。
當synchronized使用在自定義代碼塊上,能夠自定義執行該代碼塊須要的鎖對象。
注:synchronized鎖的是對象,不一樣對象鎖不一樣,如當訪問一個同步方法時,該對象的其餘同步方法也被鎖;普通同步方法與靜態同步方法互不干擾。還有synchronized關鍵字不能被繼承。
2)在線程把操做的共享數據刷新到主存以前,對共享數據的更改對其餘線程來講是不可見的,解決方法——volatile 關鍵字,保證變量會直接從主存讀取,而對變量的更新也會直接寫到主存。
voilatile只是解決可見性,對於非原子操做並不保證線程安全。
總結:原子性——原子性指的是一個操做是不可中斷的,即便是在多線程環境下,一個操做一旦開始就不會被其餘線程影響。
可見性——指的是當一個線程修改了某個共享變量的值,其餘線程是否可以立刻得知這個修改的值。
重排序——計算機在執行程序時,爲了提升性能,編譯器和處理器的經常會對指令作重排。volatile會禁用重排序。
有序性——指的是單線程內保證串行語義執行的一致性,後半句則指指令重排現象和工做內存與主內存同步延遲現象。
參考:http://blog.csdn.net/suifeng3051/article/details/52611310
http://blog.csdn.net/javazejian/article/details/72772461
https://www.cnblogs.com/wxd0108/p/5479442.html
https://www.cnblogs.com/GarfieldEr007/p/5746362.html