一、程序和進程:java
程序:一個固定的運算邏輯和數據的集合,是一個靜態的狀態,通常存儲在硬盤中安全
進程:正在運行的程序,是程序的一次運行,是一個動態的狀態多線程
二、進程和線程:併發
進程:一個正在運行的程序,有本身獨立的資源分配,是一個獨立的個體ide
線程:一個獨立的執行路徑。多線程,一個進程中可能有許多子任務,每一個線程均可以獨立的完成一個子任務,各個任務之間沒有依賴關係,能夠單獨執行。this
三、並行和併發:spa
並行:多個程序同時執行,相互獨立。線程
併發:多個任務同時發起,但不能同時執行,只能來回切換的執行。在同一個時間段內,將每一個程序都執行過。設計
問題:併發究竟是提高了效率仍是下降了效率?code
多個任務都在執行,效率提升了,但對於某一單獨任務來講是下降了。
併發技術解決了各個設備之間速率不一樣的問題(如內存和硬盤的存儲速度不一樣),大大提升了CPU的利用率。
四、多線程實現方式(3種):
繼承方式:(代碼示例)
- 寫一個類,繼承Thread
- 重寫run()方法
- 建立類對象,對象.start()方法執行
注:若使用對象.run(),則是普通的執行方法,不會開啓新線程
實現方式:(代碼示例)
- 寫一個類,實現Runnable接口
- 重寫run()方法
- 建立類對象(任務對象)
- 建立線程對象,將任務傳給線程Thread t = new Thread(任務對象名);
- t.start()啓動線程,會自動執行run()內容
兩種方式的比較:
- 代碼複雜程度:第一種方式更簡單
- 實現原理
繼承Thread,調用start()方法,本質上是調用start0()方法,是本地方法,由C語言實現,java中看不到源代碼
實現Runnable接口,是建立了一個任務對象,將對象傳給線程,再開啓線程
3.在設計實用性方面:
java中繼承都是單繼承,若是繼承了Thread,則沒法繼承其它類
Java中對接口的實現能夠多實現,不影響程序的編寫
匿名內部類實現方式:(代碼示例)
new Thread(){run () { } }.start();
new Thread(new Runnable(){run () {} });
五、多線程中的經常使用方法:(代碼示例)
1.獲取線程的名稱getName()
注意:
1.若是沒有給線程命名,則線程名字從Thread-0開始依次增長
2.可使用對象的引用調用此方法,也能夠在線程類中調用
Thread.currentThread().getName()
3.Runnable實現類中沒有此方法
2.使用對象的引用設置線程名字setName():
構造方法也可設置線程名字:Thread(Runnable 任務名, String 線程名);
對象名.setName(String name)
3.獲取當前線程對象Thread.currentThread()
4.線程休眠Thread.sleep(毫秒)
做用:當代碼在某個位置須要休息時,就使用休眠
不管哪一個線程執行到這裏都會休眠
注意:有一個異常,中斷異常InterruptedException,在run()中必須處理,不能聲明
5.守護線程:setDaemon(boolean flag)
每條線程默認都不是守護線程,只有設定flag爲true纔會成爲守護線程
特色:守護其它非守護線程,若是其它非守護線程全都掛掉則跟隨死亡
6.設置線程的優先級setPriority()
NORM_PRIORITY 5
MAX_PRIORITY 10
MIN_PRIORITY 1
六、安全問題(同步)(代碼示例:火車站購票)
多線程在操做共享數據的時候可能會產生線程不安全問題
解決方法:使用同步代碼塊
格式:synchronized(鎖對象){須要同步的代碼}
原理:在有線程處於同步代碼塊之中時,其它線程必須在代碼塊外等待,直到裏面的線程運行結束
同步方法:當一個方法中全部的代碼都在同步代碼塊中時,能夠將方法定義爲同步方法
格式:權限修飾符 synchronized 返回值類型 方法名(參數列表){方法體};
注:非靜態方法的鎖對象是this,也就是當前對象
靜態方法的鎖對象是 類名.class (在方法區的一個對象)
若是兩條線程操做相同的數據,鎖對象必須保持一致
使用什麼鎖,通常用保護的數據做爲鎖對象
七、死鎖
A線程須要甲資源,同時擁有了乙資源,B線程擁有乙資源,同時須要甲資源,兩條線程都不願釋放本身的資源,就會造成死鎖。
有了同步代碼塊的嵌套,就可能發生死鎖。某條線程獲取了外層的鎖對象A,須要內層的鎖對象B,等待;另一條線程獲取了外層的鎖對象B,須要內層的鎖對象A,等待。兩條線程就會造成死鎖。
public class Demo01 { //第一種方式:繼承Thread,重寫run方法,建立對象,對象.start() public static void main(String[] args) { SellTicket st = new SellTicket(); SellTicket st1 = new SellTicket(); SellTicket st2 = new SellTicket(); st.start(); st1.start(); st2.start(); } } class SellTicket extends Thread{ static int count=100;//使用靜態屬性共享票數 @Override public void run() { while(true){ if(count>0) { System.out.println(this.getName()); String name = Thread.currentThread().getName(); System.out.println(name+"...賣出了第"+count--+"張票"); }else { break; } } } }
public class Demo02 { //第二種方式:實現Runnable接口,重寫run方法,建立類對象(任務對象) //建立線程對象並將任務對象傳給線程,線程對象.start()啓動 public static void main(String[] args) { MyTicket mt = new MyTicket(); Thread t1 = new Thread(mt,"窗口1"); Thread t2 = new Thread(mt,"窗口2"); Thread t3 = new Thread(mt,"窗口3"); t1.start(); t2.start(); t3.start(); } } class MyTicket implements Runnable{ int count = 100; @Override public void run() { while(true){ if(count>0) { String name = Thread.currentThread().getName(); System.out.println(name+"...賣出了第"+count--+"張票"); }else { break; } } } }
public class Demo03 { //第三種方式:匿名內部類 public static void main(String[] args) { new Thread(new MyTicketWindow()).start(); new Thread(new MyTicketWindow()).start(); new Thread(new MyTicketWindow()).start(); } } class MyTicketWindow implements Runnable{ static int count = 100; static Object obj = new Object(); @Override public void run() { while(true){ synchronized (obj) { if(count>0) { try { Thread.sleep(200); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } String name = Thread.currentThread().getName(); System.out.println(name+"...賣出了第"+count--+"張票"); }else { break; } } } } }