線程知識總結

進程就是一個正在運行的程序,分配內存讓應用程序可以運行。java

 

       Windows系統號稱多任務(能夠同時運行多個應用程序)。安全

           宏觀上看:Windows確實是運行多個程序。多線程

           微觀上看:CPU快速切換執行任務,因爲速度特別快,咱們人感受不到這個切換的過程jvm

 

線程在一個進程中負責代碼的執行,就是進程中的執行路徑。ide

  

 疑問:沒有主線程,爲何代碼能夠執行?函數

        java程序在運行的時候,jvm會幫咱們建立一個主線程來執行代碼。主線程主要負責main方法中的代碼執行。this

   

 一個java程序中至少有2個線程spa

       一個主線程主要負責main方法中的代碼執行,一個垃圾回收器線程,負責垃圾回收。線程

   多線程:在一個進程中多個線程同時執行不一樣的任務。code

   「同時」:單核CPU快速切換多個線程執行任務

            速度特別快,人感受不到切換。

 

多線程的好處:

       1.解決一個進程中同時執行多個任務的問題、

       2.提升資源的利用率。

  

多線程的弊端:

       1.增長CPU的負擔。線程不是越多越好。

       2.下降了一個進程中線程的執行效率。

       3.容易引起線程安全問題。

       4.出現死鎖現象。

 

 java中建立線程有2種方式

      線程的定義方式一Thread (線程類)

        1.須要定義一個類來繼承Thread類。

        2.重寫thread類中run方法,把自定義線程的任務代碼寫在run方法中。

               * 每個線程都有本身的任務代碼,jvm建立的主線程任務代碼就是main方法,

               * 自定義的線程的任務代碼就寫在run方法中,自定義的線程就須要執行run方法中的代碼。

        3.建立Thread的子類,而且調用start方法開啓線程。

           

     注意點:一旦線程開啓了,會默認執行線程對象中的run方法,可是千萬不要本身直接調用run方法,若是直接調用了run方法,就和普通方法沒有區別。

 

    Java 是單線程,若是一個類已經繼承了別的類,這個時候就不可以經過繼承thread類來建立線程了。

  

線程的使用細節:

       1.線程的啓動使用父類的start()方法

       2.若是線程對象直接調用run(),那麼JVm不會看成線程來運行,會認爲是普通的方法調用。

       3.線程的啓動只能由一次,不然拋出異常

       4.能夠直接建立Thread類的對象並啓動該線程,可是若是沒有重寫run(),什麼也不執行。

       5.匿名內部類的線程實現方式

 

   線程的定義方式二:

     1.自定義一個類實現Runable接口  , 接口中就會提供一個run方法

     2.實現Runable接口中的run方法。將線程中的任務寫在run方法中

     3.建立Runable接口的實現類對象

       注意點:實現runnable接口的類不是一個實現類,他是沒有能力開啓線程的只有是thread或者他的子類纔是線程類,只有他們纔有開啓線程的能力。

     4.建立一個Thread對象,並把Runable實現類建立的對象做爲參數。

     5.調用Thread對象的start方法來開啓線程

  

 問題 爲何要將Runable接口實現類的對象做爲參數傳遞?

      爲了讓對象中的run方法可以在線程中的run方法中執行。也就是可以將對象中的run方法最爲線程中的任務來執行

     

 *  推薦使用 :第二種方式  實現Runable.

 

 *  java 是單繼承 ,多實現的

    售票的線程方式一(thread):

 

class SaleTickets extends Thread {
    static int num = 50; // 總票數 共享的數據,三個窗口同時操做同一份數據
    //static Object o = new Object();
    public SaleTickets (String name) {
        super(name);
    }
   // 重寫run方法:賣票的任務
    public void run() {
       
        while (true) {
            synchronized ("hh") { //任意類型的對象,鎖對象應該是同一個對象
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    // TODO: handle exception
                    e.printStackTrace();
                }
                if(num > 0) {
                    System.out.println(this.getName() + "賣了第" + num + "票");
                    num--;
                
                } else {
                    System.out.println("票已售完");
                    break;
                }
            }
        
            
        }
    }
    
}
public class Demo4 {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
       SaleTickets t1 = new SaleTickets("窗口1");
       SaleTickets t2 = new SaleTickets("窗口2");
       SaleTickets t3 = new SaleTickets("窗口3");
       t1.start();
       t2.start();
       t3.start();
    }

}

 

售票的線程方式二(Runnable):

class SaleTickets1 implements Runnable {
    static int num = 50;
     public void run() {
         while (true) {
             synchronized ("djj") {
                 if (num > 0) {
                        System.out.println(Thread.currentThread().getName() + "賣出第" + num + "張票");
                        num--;
                    } else {
                        System.out.println("票已售盡");
                         break;
                    }
             }
            
        }
        
    }
}
public class Demo8 {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //建立實現類對象
       SaleTickets1 st = new SaleTickets1();
       // 建立三個線程對象
       Thread t = new Thread(st, "窗口1");
       Thread t1 = new Thread(st, "窗口2");
       Thread t2 = new Thread(st, "窗口3");
       t.start();
       t1.start();
       t2.start();
    }

}
 

 

java給線程加鎖 :

 

解決線程安全問題的手段:

 

經過同步代碼的方式:

 

    方式一:同步代碼塊

 

       鎖對象能夠是任意一個java中的對象

 

        java中的任意一個對象都會有一個對象的狀態 ,就能夠經過對象的狀態來做爲鎖的一個標識符。

 

     state = 0 表示鎖是關閉   state = 1 表示鎖打開。

 

       synchronized (鎖對象) {

   }

 

同步代碼塊的使用注意點

 

         1.任意一個對象均可以作鎖對象

 

        2.若是你在同步代碼塊中調用了sleep方法 ,不會釋放鎖對象

 

       3.只有真正存在線程安全的時候才須要使用同步代碼塊,不然會下降執行效率

 

       4.多線程操做鎖對象必須是惟一的 ,不然無效

 

方式二:同步函數

 

       寫法:用synchronize來修飾方法。

 

       若是同步函數是一個非靜態的函數:鎖對象就是調用者對象。

 

       若是同步函數是一個靜態的函數:鎖對象同步函數是所在類的字節碼(Class對象)

 

同步函數和同步代碼塊的區別:

 

       1.同步代碼塊,能夠隨意肯定同步代碼的範圍,同步函數只能同步整個函數的代碼。

 

       2.同步代碼塊的鎖對象能夠本身任意指定,同步函數的鎖對象是固定的。

 

不知道何時安全何時不安全。

 

出現線程安全的問題根本緣由:

 

     1.存在兩個或兩個以上的線程。而且線程之間共享着一個資源。

 

     2.多個語句操做了共享資源

 

線程死鎖:

 

 可是若是使用不當會致使線程死鎖問題:

  A線程等B線程完成, B線程又在等A線程   結果兩我的就一直等下去了 ,這個時候就形成了線程死鎖。

  線程死鎖不必定會出現,有可能會出現。

  死鎖現象的解決方案 :  沒有方案 ,儘可能避免發生。

 

實例:

class DeadLock extends Thread { public DeadLock(String name){ super(name); } @Override public void run() { if("張三".equals(Thread.currentThread().getName())){ synchronized ("遙控器") { //鎖對象就鎖住了  System.out.println("張三拿到了遙控器 ,準備去拿電池"); synchronized ("電池") {//已經被鎖住了  System.out.println("張三拿到了遙控器和電池,開着空調,在也 不冷了"); } } }else if("老王".equals(Thread.currentThread().getName())){ synchronized ("電池") { //鎖也被鎖住了 電池對象的狀態 變爲鎖住的狀態  System.out.println("老王拿到電池,準備去拿遙控器"); synchronized ("遙控器") { //遙控器也被鎖住了  System.out.println("老王拿到了遙控器和電池,開着空調,在也 不冷了"); } } } } } public class Demo6 { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub  DeadLock t1 = new DeadLock("張三"); t1.start(); DeadLock t2 = new DeadLock("老王"); t2.start(); 

 

線程的通信:

  線程的通信:一個線程完成本身的任務,去通知另一個線程去完成另一個任務。

 

    wait();  等待      若是線程執行了wait方法 ,那麼該線程就會處於一個等待狀態,等待狀態的線程必需要經過其餘線程來調用

    notify()方法來喚醒。

 

    notify();喚醒   隨機喚醒線程池中的一個線程。

     notifyAll(); 喚醒全部等待的線程。

 

 waitnotify的使用注意點 :

   1.wait方法和notify方法是屬性Object對象

   2.wait方法和notify方法必須在同步線程中執行

   3.wait方法和notify方法必須有鎖對象來調用

 

消費者和生產者之間的通信:

class Product {
    
    String name;
    double price;
    
}

class Producter extends Thread{  //生產產品
    Product p;
    
    public Producter(Product p){
        
        this.p = p;
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        
        for(int i = 0;i<50;i++){
            
            synchronized (p) {
                
                if(i % 2 == 0){
                    p.name = "蘋果";
                    p.price = 3.5;
                    System.out.println(p.name+":"+p.price);
                }else {
                    
                    p.name = "香蕉";
                    p.price = 2.0;
                    System.out.println(p.name+":"+p.price);
                }
                
                //產品以經生產出來 喚醒消費者來消費
                p.notify();
                
                try {
                    p.wait(); // 等待消費者提醒
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                
                
            }
        }
        
    }
}

class Custem extends Thread{
    
    Product p; // 消費者消費的產品
    
    public Custem(Product p){
        
        this.p = p;
    }
    
    @Override
    public void run() {
        // TODO Auto-generated method stub
        
        for (int i = 0;i<50;i++){
            synchronized (p) {
                //經過鎖對象來調用
                if(p.name != null){
                    System.out.println("吃"+p.name+":"+p.price);
                } // 沒有產品  告訴生產者須要生產產品
                    
                //喚醒生產者
                p.notify();
                try {
                    p.wait();  //等待產品建立
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
}

public class Demo9 {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //建立一個產品對象
        Product p = new Product();
        
        //建立一個生產者
        Producter t1 = new Producter(p);
        
        //建立一個消費者
        Custem t2 = new Custem(p);
        
        t1.start();
        t2.start();
        

    }

}
相關文章
相關標籤/搜索