中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JAVA多線程的用法

發布時間:2020-07-30 13:41:36 來源:億速云 閱讀:131 作者:小豬 欄目:開發技術

這篇文章主要講解了JAVA多線程的用法,內容清晰明了,對此有興趣的小伙伴可以學習一下,相信大家閱讀完之后會有幫助。

線程概念

進程:啟動一個應用程序就叫一個進程。 接著又啟動一個應用程序,這叫兩個進程。每個進程都有一個獨立的內存空間;進程也是程序的一次執行過程,是系統運行程序的基本單位;系統運行一個程序即是一個進程從創建、運行到消亡的過程。

線程:線程是在進程內部同時做的事情,一個進程中可以有多個線程,這個應用程序也可以稱之為多線程程序。

一個程序運行后至少有一個進程,一個進程中可以包含多個線程

線程調度:

  • 分時調度:所有線程輪流使用 CPU 的使用權,平均分配每個線程占用 CPU 的時間。
  • 搶占式調度:優先讓優先級高的線程使用 CPU,如果線程的優先級相同,那么會隨機選擇一個(線程隨機性),Java使用的為搶占式調度。
     

創建多線程

方法一:創建Thread類的子類

  • 創建Thread類的子類,并重寫該類的run()方法,設置線程任務。
  • 創建Thread子類的實例,即創建了線程對象
  • 調用線程對象的start()方法來啟動該線程
//方法一:
//定義Thread類的子類,并重寫該類的run()方法
public class MyThreadDemo01 extends Thread {
  @Override
  public void run() {
    for (int i = 0; i < 20 ; i++) {
      System.out.println(getName()+"-->"+i);
    }
  }
}
//主線程
public class MainThread01 {
  public static void main(String[] args) {
    //創建Thread子類的實例,即創建了線程對象
    MyThreadDemo01 thread01 = new MyThreadDemo01();

    //調用線程對象的start()方法來啟動該線程
    thread01.start();

    for (int i = 0; i < 10 ; i++) {
      System.out.println(Thread.currentThread().getName()+"-->"+i);
    }
  }
}

public static Thread currentThread() :返回對當前正在執行的線程對象的引用。

public String getName() :獲取當前線程名稱。

public void start() :導致此線程開始執行; Java虛擬機調用此線程的run方法。

public void run() :此線程要執行的任務在此處定義代碼。

public static void sleep(long millis) :使當前正在執行的線程以指定的毫秒數暫停(暫時停止執行)。

方法二:實現Runnable接口

  • 定義Runnable接口的實現類,并重寫該接口的run()方法,設置線程任務
  • 創建Runnable實現類對象
  • 創建Thread類的對象,并且該對象構造方法中傳遞Runnable實現類對象
  • 調用Thread對象的start()方法來啟動線程
//方法二:
//定義Runnable接口的實現類,并重寫該接口的run()方法,設置線程任務
public class MyThreadDemo02 implements Runnable{
  @Override
  public void run() {
    for (int i = 0; i < 10 ; i++) {
      System.out.println(Thread.currentThread().getName()+"-->"+i);
    }
  }
}
 //主線程
public class MainThread {
  public static void main(String[] args) {  
    //創建Runnable實現類對象
    MyThreadDemo02 runnable = new MyThreadDemo02();

    //創建Thread類的對象,并且該對象構造方法中傳遞Runnable實現類對象
    Thread thread02 = new Thread(runnable);

    //調用Thread對象的start()方法來啟動線程
    thread02.start();

    for (int i = 0; i < 20 ; i++) {
      System.out.println(Thread.currentThread().getName()+"-->"+i);
    }
  }
}

方法三:匿名內部類方式

  • 匿名內部類能夠簡化程序
//方法三:匿名內部類
public class MainThread {
  public static void main(String[] args) {
    //Thread方式
    new Thread(){
      @Override
      public void run() {
        for (int i = 0; i < 10 ; i++) {
          System.out.println(Thread.currentThread().getName()+"-->"+i);
        }
      }
    }.start();
    //Runnable接口方式
	 new Thread(new Runnable() {
      @Override
      public void run() {
        for (int i = 0; i < 10 ; i++) {
          System.out.println(Thread.currentThread().getName()+"-->"+i);
        }
      }
    }).start();
    ////////////////////////////////////////////////

    for (int i = 0; i < 20 ; i++) {
      System.out.println(Thread.currentThread().getName()+"-->"+i);
    }
  }
}

線程安全問題

多線程訪問共享數據,,且多個線程中對資源有寫的操作,就會出現線程安全問題

線程安全問題都是由全局變量及靜態變量引起的。若每個線程中對全局變量、靜態變量只有讀操作,而無寫操作,一般來說,這個全局變量是線程安全的;若有多個線程同時執行寫操作,一般都需要考慮線程同步, 否則的話就可能影響線程安全。

解決線程安全問題采用線程同步機制,主要有以下三種方式:

  • 同步代碼塊
  • 同步方法
  • 鎖機制

同步代碼塊

同步代碼塊:synchronized 關鍵字可以用于方法中的某個區塊中,表示只對這個區塊的資源實行互斥訪問。

  • 格式:synchronized(鎖對象){ //訪問共享數據的代碼 }
  • 鎖對象可以是任意類型
  • 多個線程對象要使用同一把鎖
  • 鎖對象是將同步代碼塊鎖住,只讓線程在同步代碼塊中執行
public class SafeRunnableDemo implements Runnable {
  private int ticket = 100;

  //同步代碼塊
  //創建鎖對象
  Object lock = new Object();

  @Override
  public void run() {
    while (true){
      //鎖住同步代碼塊
      synchronized (lock){
        if (ticket > 0) {
          System.out.println(Thread.currentThread().getName() + "正在賣第" + ticket + "張");
          ticket--;
        }
      }
    }
  }
}

同步方法

同步方法:使用synchronized修飾的方法,就叫做同步方法,保證A線程執行該方法的時候,其他線程只能在方法外等著

  • 格式:修飾符 synchronized 返回值類型 方法名(參數列表) { //訪問共享數據的代碼 }
  • 把共享了同步數據的代碼抽取出來,放入同步方法中
public class SafeRunnableDemo implements Runnable {
  private int ticket = 100;

  //同步方法
  //定義一個同步方法
  public synchronized void lock(){
    //同步方法鎖住代碼塊
    if (ticket > 0) {
      System.out.println(Thread.currentThread().getName() + "正在賣第" + ticket + "張");
      ticket--;
    }
  }

  //重寫run并使用同步方法
  @Override
  public void run() {
    while (true){
      lock();
    }
  }
}

Lock鎖

Lock提供了比synchronized更廣泛的鎖操作

  • 在Lock接口中 void lock() 獲取鎖,void unlock() 釋放鎖
  • 需要在成員位置處創建ReentraLock對象,在共享數據代碼塊之前調用方法lock()獲取鎖,在之后用unlock()方法釋放鎖
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class SafeRunnableDemo implements Runnable {
  private int ticket = 100;

  //Lock鎖方法
  //創建ReentrantLock對象
  Lock lock = new ReentrantLock();
  @Override
  public void run() {
    while (true){
      //在可能出現問題的代碼塊之前用lock()方法
      lock.lock();
      if (ticket > 0) {
        System.out.println(Thread.currentThread().getName() + "正在賣第" + ticket + "張");
        ticket--;
      }
      //在可能出現問題的代碼塊之后用unlock()方法
      lock.unlock();
    }
  }
}

線程機制

  • NEW(新建):線程剛被創建,但是并未啟動。還沒調用start()方法。
  • Runnable(可運行):線程可以在java虛擬機中運行的狀態,可能正在運行自己代碼,也可能沒有,這取決于操作系統處理器。
  • Blocked(鎖阻塞):當一個線程試圖獲取一個對象鎖,而該對象鎖被其他的線程持有,則該線程進入Blocked狀態;當該線程持有鎖時,該線程將變成Runnable狀態。
  • Waiting(無限等待):一個線程在等待另一個線程執行一個(喚醒)動作時,該線程進入Waiting狀態。進入這個狀態后是不能自動喚醒的,必須等待另一個線程調用notify()或者notifyAll()方法才能夠喚醒。
  • Timed Waiting(計時等待):同waiting狀態,有幾個方法有超時參數,調用他們將進入Timed Waiting狀態。這一狀態 將一直保持到超時期滿或者接收到喚醒通知。帶有超時參數的常用方法有Thread.sleep()、Object.wait()。
  • Teminated(被終止):因為run方法正常退出而死亡,或者因為沒有捕獲的異常終止了run方法而死亡。

一個調用了某個對象的 Object.wait() 方法的線程會等待另一個線程調用此對象Object.notify()方法 或 Object.notifyAll()方法。

其實waiting狀態并不是一個線程的操作,它體現的是多個線程間的通信,可以理解為多個線程之間的協作關系, 多個線程會爭取鎖,同時相互之間又存在協作關系。

當多個線程協作時,比如A,B線程,如果A線程在Runnable(可運行)狀態中調用了wait()方法那么A線程就進入 了Waiting(無限等待)狀態,同時失去了同步鎖。假如這個時候B線程獲取到了同步鎖,在運行狀態中調用了 notify()方法,那么就會將無限等待的A線程喚醒。注意是喚醒,如果獲取到鎖對象,那么A線程喚醒后就進入 Runnable(可運行)狀態;如果沒有獲取鎖對象,那么就進入到Blocked(鎖阻塞狀態)。

public class WaitAndSleep {
  public static void main(String[] args) {
    //創建鎖對象
    Object lock = new Object();

    //匿名內部類創建線程1
    new Thread(){
      @Override
      public void run() {
        System.out.println(Thread.currentThread().getName()+"需要買票");
        //用同步代碼塊包裹
        synchronized (lock){
          try {
            //lock.wait(5000);//到5秒自動醒來
            lock.wait();//進入無限等待,需要喚醒
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
        System.out.println(Thread.currentThread().getName()+"買到了票");
      }
    }.start();

    //匿名內部類創建線程2
    new Thread(){
      @Override
      public void run() {
        try {
          Thread.sleep(5000);//等待5秒
          System.out.println(Thread.currentThread().getName()+"出票了");
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        //用同步代碼塊包裹
        synchronized (lock){
          lock.notify();//如果有多個線程等待,隨機喚醒一個
          //lock.notifyAll();//喚醒所有等待的線程
        }
      }
    }.start();
  }
}

線程池

當在系統中用到了很多的線程,大量的啟動和結束動作會導致系統的性能變卡,響應變慢,采用線程池可以解決這個問題。線程池就相當于一個容器(如同ArrayList),執行的任務放入線程池中,多出來的任務就等待線程池中的任務執行完再放入。

  • 使用線程池的工廠類 Executors 里的靜態方法 newFixedThreadPool 生產指定線程數量的線程池,返回為ExecutorService接口
  • 創建一個類實現Runnable接口,重寫run方法,設置線程任務
  • 調用ExecutorService中的submit方法,傳遞線程任務,開啟線程
  • 銷毀線程池:ExecutorService中的shutdown方法
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

//線程池
public class ThreadPoolMain {
  public static void main(String[] args) {
    //使用線程池的工廠類 Executors里的靜態方法 newFixedThreadPool
    // 生產指定線程數量的線程池,返回為ExecutorService接口
    ExecutorService es = Executors.newFixedThreadPool(2);

    //調用ExecutorService中的submit方法,傳遞線程任務,開啟線程
    es.submit(new ThreadPoolDemo01());
  }
}

//////////////////////////////////////////////////////

//創建一個類實現Runnable接口,重寫run方法,設置線程任務
public class ThreadPoolDemo01 implements Runnable{
  @Override
  public void run() {
    ...
  }
}

看完上述內容,是不是對JAVA多線程的用法有進一步的了解,如果還想學習更多內容,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

沾益县| 柯坪县| 偃师市| 淮安市| 麦盖提县| 达孜县| 惠安县| 称多县| 大邑县| 河东区| 南康市| 保靖县| 亚东县| 中宁县| 宜君县| 青海省| 平罗县| 夹江县| 云浮市| 上高县| 临猗县| 城固县| 广安市| 汶上县| 手游| 密云县| 衡南县| 灵寿县| 牟定县| 桦南县| 清河县| 开阳县| 彩票| 当涂县| 惠水县| 武宁县| 县级市| 安福县| 南宫市| 阿鲁科尔沁旗| 大理市|