Java 多線程

一、程序和進程:java

  程序:一個固定的運算邏輯和數據的集合,是一個靜態的狀態,通常存儲在硬盤中安全

  進程:正在運行的程序,是程序的一次運行,是一個動態的狀態多線程

二、進程和線程:併發

  進程:一個正在運行的程序,有本身獨立的資源分配,是一個獨立的個體ide

  線程:一個獨立的執行路徑。多線程,一個進程中可能有許多子任務,每一個線程均可以獨立的完成一個子任務,各個任務之間沒有依賴關係,能夠單獨執行。this

三、並行和併發:spa

  並行:多個程序同時執行,相互獨立。線程

  併發:多個任務同時發起,但不能同時執行,只能來回切換的執行。在同一個時間段內,將每一個程序都執行過。設計

  問題:併發究竟是提高了效率仍是下降了效率?code

    多個任務都在執行,效率提升了,但對於某一單獨任務來講是下降了。

    併發技術解決了各個設備之間速率不一樣的問題(如內存和硬盤的存儲速度不一樣),大大提升了CPU的利用率。

四、多線程實現方式(3種):

  繼承方式:(代碼示例)

  1. 寫一個類,繼承Thread
  2. 重寫run()方法
  3. 建立類對象,對象.start()方法執行

  注:若使用對象.run(),則是普通的執行方法,不會開啓新線程

  實現方式:(代碼示例)

  1. 寫一個類,實現Runnable接口
  2. 重寫run()方法
  3. 建立類對象(任務對象)
  4. 建立線程對象,將任務傳給線程Thread t = new Thread(任務對象名);
  5. t.start()啓動線程,會自動執行run()內容

  兩種方式的比較:

  1. 代碼複雜程度:第一種方式更簡單
  2. 實現原理

    繼承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; } } } } }
多線程第三種實現方式
相關文章
相關標籤/搜索