作java web開發,一直以來比較依賴java框架和oracle數據庫的功能。由於通常遇到高併發的狀況並很少,企業內軟件多半用戶數很少,即便偶爾遇到,也都在oracle數據庫中處理了。 java
對java的多線程開發,一直以來只有一個簡單的概念,沒有深刻使用理解過,但願此次利用網上的內容,可以回顧一下。 web
進程:一個內存中運行的應用程序,每一個進程都有本身獨立的一塊內存空間,一個進程中能夠啓動多個線程。好比在Windows系統中,一個運行的exe就是一個進程。 數據庫
線程:進程中的一個執行流程,一個進程中能夠運行多個線程。好比java.exe進程中能夠運行不少線程。線程老是屬於某個進程,進程中的多個線程共享進程的內存。 編程
操做系統中的進程是資源的組織單位。進程有一個包含了程序內容和數據的地址空間,以及其它的資源,包括打開的文件、子進程和信號處理器等。不一樣進程的地址空間是互相隔離的。而線程表示的是程序的執行流程,是CPU調度的基本單位。線程有本身的程序計數器、寄存器、棧和幀等。引入線程的動機在於操做系統中阻塞式I/O的存在。當一個線程所執行的I/O被阻塞的時候,同一進程中的其它線程可使用CPU來進行計算。這樣的話,就提升了應用的執行效率。線程的概念在主流的操做系統和編程語言中都獲得了支持。 多線程
線程與進程的區別: 併發
地址空間: 進程內的一個執行單元;進程至少有一個線程,它們共享進程的地址空間;而進程有本身獨立的地址空間; oracle
資源擁有: 進程是資源分配和擁有的單位,同一個進程內的線程共享進程的資源 框架
線程是處理器調度的基本單位,但進程不是. 編程語言
兩者都可併發執行. ide
線程共有下面4種狀態:
新建狀態(New):新建立了一個線程對象,當你用new建立一個線程時,該線程還沒有運行。
就緒狀態(Runnable):線程對象建立後,其餘線程調用了該對象的start()方法。該狀態的線程位於可運行線程池中,變得可運行,等待獲取CPU的使用權。
運行狀態(Running):就緒狀態的線程獲取了CPU,執行程序代碼。
阻塞狀態(Blocked):阻塞狀態是線程由於某種緣由放棄CPU使用權,暫時中止運行。直到線程進入就緒狀態,纔有機會轉到運行狀態。阻塞的狀況分三種:
等待阻塞:運行的線程執行wait()方法,JVM會把該線程放入等待池中。
同步阻塞:運行的線程在獲取對象的同步鎖時,若該同步鎖被別的線程佔用,則JVM把該線程放入鎖。
其餘阻塞:運行的線程執行sleep()或join()方法,或者發出了I/O請求時,JVM會把該線程置爲阻塞狀態。當sleep()狀態超時、join()等待線程終止或者超時、或者I/O處理完畢時,線程從新轉入就緒狀態。
死亡狀態(Dead):
因爲run方法的正常退出而天然死亡;
沒有捕獲到的異常事件終止了run方法的執行,從而致使線程忽然死亡
狀態之間的轉換能夠用下面的兩張圖來展現
繼承Thread類
public class TestThread extends Thread { @Override public void run() { super.run(); for (int i = 0; i < 1000; i++) { System.out.println(「T-「 + i);
try { Thread.sleep(800); } catch (InterruptedException e) { e.printStackTrace(); } } } }
實現Runnable接口
public class TestRunnable implements Runnable {
@Override public void run() { for (int i = 0; i < 1000; i++) { System.out.println("R-" + i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { Thread runnable = new Thread(new TestRunnable()); Thread thread = new TestThread(); thread.start(); runnable.start(); } }
運行結果:
守護線程一般爲普通線程提供服務,它們一般有一個無限循環,等待服務請求或執行線程的任務,在沒有其餘的非守護線程運行時,守護線程將中止工做。即便你不建立任何線程,Java應用程序在默認狀況下建立多個線程。他們大可能是守護線程,主要用於處理任務,如垃圾收集或JMX。
守護線程的特色:
優先級很是低
只有當同一個程序的任何其餘線程正在運行時執行。
當線程只剩下守護線程的時候,JVM就會退出.可是若是還有其餘的任意一個用戶線程還在,JVM就不會退出.
用戶線程和守護線程二者幾乎沒有區別,惟一的不一樣之處就在於虛擬機的離開:若是用戶線程已經所有退出運行了,只剩下守護線程存在了,虛擬機也就退出了。 由於沒有了被守護者,守護線程也就沒有工做可作了,也就沒有繼續運行程序的必要了
在JAVA中經過調方法Thread.setDaemon(true)將線程轉爲守護線程。但須要注意的有:
但必須在調Thread.start()方法以前,由於一旦線程正在運行,你不能修改它的守護進程的狀態。
在Daemon線程中產生的新線程也是Daemon的
守護線程應該永遠不去訪問固有資源,如文件、數據庫,由於它會在任什麼時候候甚至在一個操做的中間發生中斷。
代碼示例:
public class DaemonThread { public static void main(String[] args) { Thread thread = new Thread(new ThreadRunnable()); thread.setDaemon(true); thread.start(); try { Thread.sleep(750); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Main Thread ending"); } } class ThreadRunnable implements Runnable { @Override public void run() { int count = 0; while (true) { System.out.println("Hello from Worker " + count++); try { Thread.sleep(350); } catch (InterruptedException e) { e.printStackTrace(); } } } }
運行結果:
Hello from Worker 0 Hello from Worker 1 Hello from Worker 2 Main Thread ending
從運行結果能夠看到,隨着主線程的結果,原本是無限循環的子線程,也跟着結束了,說明守護線程不會影響程序的結束。
線程的狀態轉換,主要是由sleep()、wait()、yeid()、join()等幾個方法來實現(stop()、interrupt()等方法貌似都有必定的問題,不是很推薦使用)。
sleep方法與wait方法的區別:
sleep方法是靜態方法,wait方法是非靜態方法。 sleep方法在時間到後會本身「醒來」,但wait不能,必須由其它線程經過notify(All)方法讓它「醒來」。 sleep方法一般用在不須要等待資源狀況下的阻塞,像等待線程、數據庫鏈接的狀況通常用wait。
sleep/wait與yeld方法的區別:
調用sleep或wait方法後,線程即進入block狀態,而調用yeld方法後,線程進入runnable狀態。
wait與join方法的區別:
wait方法體現了線程之間的互斥關係,而join方法體現了線程之間的同步關係。 wait方法必須由其它線程來解鎖,而join方法不須要,只要被等待線程執行完畢,當前線程自動變爲就緒。 join方法的一個用途就是讓子線程在完成業務邏輯執行以前,主線程一直等待直到全部子線程執行完畢。