欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JAVA多線程編程實(shí)例詳解

 更新時(shí)間:2019年09月04日 10:48:06   作者:doubly_yi  
這篇文章主要介紹了JAVA多線程編程,結(jié)合實(shí)例形式總結(jié)分析了多線程、鎖、線程池等相關(guān)原理及使用技巧,需要的朋友可以參考下

本文實(shí)例講述了JAVA多線程編程。分享給大家供大家參考,具體如下:

  • 進(jìn)程是系統(tǒng)進(jìn)行資源調(diào)度和分配的一個(gè)獨(dú)立單位。
  • 進(jìn)程的特點(diǎn)
    獨(dú)立性:進(jìn)程是系統(tǒng)中獨(dú)立存在的實(shí)體,擁有自己的獨(dú)立資源和私有空間。在沒有經(jīng)過進(jìn)程本身允許的情況下,不能直接訪問其他進(jìn)程。
    動(dòng)態(tài)性:進(jìn)程與程序的區(qū)別在于,前者是一個(gè)正在系統(tǒng)中活動(dòng)的指令,而后者僅僅是一個(gè)靜態(tài)的指令集合
    并發(fā)性:多個(gè)進(jìn)程可以在單個(gè)處理器上并發(fā)執(zhí)行,而不受影響。

并發(fā)性和并行性的區(qū)別:
并行性:在同一時(shí)刻,有多條指令在多個(gè)處理器上同時(shí)執(zhí)行(多個(gè)CPU)
并發(fā)性:在同一時(shí)刻只能有一條指令執(zhí)行,但多個(gè)進(jìn)程指令被快速輪換執(zhí)行,使得宏觀上具有多個(gè)進(jìn)程同時(shí)執(zhí)行的效果(單核)。

  • 通過繼承Thread類來創(chuàng)建并啟動(dòng)多線程
public class Deom_1 extends Thread{

  public void run(){
      super.run();
      System.out.println("MyThread01");
    }


  public static void main(String[] args){
    Deom_1 demo=new Deom_1();
    demo.setName("Demo_1");
    demo.start();
    System.out.println("當(dāng)前線程的名字:"+Thread.currentThread().getName()+" 運(yùn)行結(jié)束");
  }
}

多次調(diào)用start會(huì)拋出java.lang.IllegalThreadStateException異常
如果只調(diào)用run(),不調(diào)用start()方法,就相當(dāng)于調(diào)用了一個(gè)普通的函數(shù),實(shí)際上還是在同一個(gè)線程中運(yùn)行的run()方法。

  • 多線程編程時(shí)不要忘記了Java程序運(yùn)行時(shí)默認(rèn)的主線程,main方法的方法體就是主線程的線程執(zhí)行體
  • 使用繼承Thread類的方法來創(chuàng)建線程類,多條線程之間無法共享線程的實(shí)例變量
  • 實(shí)現(xiàn)Runnable接口創(chuàng)建線程類
//通過實(shí)現(xiàn)Runnable接口來創(chuàng)建線程類
public class SecondThread implements Runnable
{
  private int i ;
  //run方法同樣是線程執(zhí)行體
  public void run()
  {
    for ( ; i < 20 ; i++ )
    {
      //當(dāng)線程類實(shí)現(xiàn)Runnable接口時(shí),
      //如果想獲取當(dāng)前線程,只能用Thread.currentThread()方法。
      System.out.println(Thread.currentThread().getName() + " " + i);
    }
  }

  public static void main(String[] args) 
  {
    for (int i = 0; i < 50; i++)
    {
      System.out.println(Thread.currentThread().getName() + " " + i);
      if (i == 20)
      {
        SecondThread st = new SecondThread();
        //通過new Thread(target , name)方法創(chuàng)建新線程
        new Thread(st , "新線程1").start();
        new Thread(st , "新線程2").start();
      }
    }
  }
}
  • 采用實(shí)現(xiàn)繼承方式的多線程:
    編程相對(duì)簡(jiǎn)單
    多條線程之間無法共享線程類實(shí)例變量
    繼承Thread類之后就不能繼承其他的父類

  • 采用實(shí)現(xiàn)接口的方式的多線程:
    線程類只是實(shí)現(xiàn)了Runnable接口,還可以繼承其他類
    在這種方式下,可以多個(gè)線程共享同一個(gè)對(duì)象,非常適合多個(gè)相同線程來處理同一份資源的情況。
    編程稍稍復(fù)雜一點(diǎn)

  • 線程的生命周期:新建(NEW)、就緒(Runnable)、運(yùn)行(Running)、阻塞(Blocked)、死亡(Dead)

  • 當(dāng)程序使用new關(guān)鍵字創(chuàng)建一個(gè)線程后,該線程就處于新建狀態(tài);當(dāng)線程對(duì)象調(diào)用了start()方法之后,該線程就處于就緒狀態(tài);如果處于就緒狀態(tài)的線程獲得了CPU,開始執(zhí)行run方法的線程執(zhí)行體,則該線程就處于運(yùn)行狀態(tài);但是它不可能一直處于運(yùn)行狀態(tài),可能會(huì)被中斷進(jìn)入阻塞狀態(tài);線程運(yùn)行結(jié)束后就會(huì)進(jìn)入到死亡狀態(tài)。

  • 線程進(jìn)入阻塞狀態(tài)的情況:
    線程調(diào)用了sleep方法主動(dòng)放棄所占有的資源
    線程調(diào)用了一個(gè)阻塞式IO方法,在該方法返回的時(shí)候被阻塞
    線程嘗試獲取一個(gè)同步監(jiān)聽器,但是被其他線程占有
    在等待某個(gè)通知
    調(diào)用線程suspend方法掛起,不推薦使用容易造成死鎖。

  • 線程進(jìn)入就緒狀態(tài)的情況:
    調(diào)用sleep方法的線程經(jīng)過了指定時(shí)間
    線程調(diào)用的阻塞式IO方法已經(jīng)返回
    線程成功獲取試圖取得同步監(jiān)聽器
    線程在等待某個(gè)通知,其他線程發(fā)出一個(gè)通知
    處于掛起狀態(tài)的線程調(diào)用了resume恢復(fù)方法

進(jìn)入阻塞狀態(tài)的線程在獲得執(zhí)行機(jī)會(huì)后重新進(jìn)入就緒狀態(tài),而不是運(yùn)行狀態(tài)。

  • 線程進(jìn)入死亡狀態(tài)的情況:
    run()方法執(zhí)行完成,線程正常結(jié)束
    線程拋出一個(gè)未捕獲的異?;蛘咤e(cuò)誤
    直接調(diào)用該線程的stop方法來結(jié)束該線程——該方法容易導(dǎo)致死鎖,通常不推薦。

當(dāng)主線程結(jié)束的時(shí)候,其他線程不受影響。一旦子線程啟動(dòng)它就擁有和主線程一樣的地位。

  • 不要試圖對(duì)一個(gè)已經(jīng)死亡的線程調(diào)用start()方法使它重新啟動(dòng),會(huì)拋出IllegalThreadStateException異常。調(diào)用線程的isAlive()方法可以測(cè)試某條線程是否死亡。

  • JAVA中控制線程的方法:
    join線程
    后臺(tái)線程
    線程睡眠:sleep
    線程讓步:yield
    改變線程優(yōu)先級(jí)

  • join線程
    join():等待被join的線程執(zhí)行完成
    join(long millis):等待被join的線程時(shí)間最長(zhǎng)millis毫秒
    join(long millis, int nanos):等待被join的線程的時(shí)間最長(zhǎng)millis毫秒加上nanos微秒

  • 后臺(tái)線程:任務(wù)是給其他線程提供服務(wù),成為“后臺(tái)線程”、“守候線程”。如果說有的前臺(tái)線程死亡,后臺(tái)線程會(huì)自動(dòng)死亡。

調(diào)用Thread類的setDaemon(true)方法可以將指定線程設(shè)置為后臺(tái)線程。該方法一定要在啟動(dòng)線程之前設(shè)置,否則會(huì)發(fā)生異常。同時(shí)提供isDaemon()方法判斷是否是后臺(tái)線程。主線程一般默認(rèn)為前臺(tái)線程。前臺(tái)線程創(chuàng)建的子線程默認(rèn)是前臺(tái),后臺(tái)線程創(chuàng)建的子線程默認(rèn)是后臺(tái)。

  • 改變線程的優(yōu)先級(jí)
PriorityTest low = new PriorityTest("低級(jí)");
low.start();
System.out.println("創(chuàng)建之初的優(yōu)先級(jí):" + low.getPriority());
//設(shè)置該線程為最低優(yōu)先級(jí)
low.setPriority(Thread.MIN_PRIORITY);
PriorityTest high = new PriorityTest("高級(jí)");
high.start();
System.out.println("創(chuàng)建之初的優(yōu)先級(jí):" + high.getPriority());
//設(shè)置該線程為最高優(yōu)先級(jí)
high.setPriority(Thread.MAX_PRIORITY);

每個(gè)線程的默認(rèn)優(yōu)先級(jí)都與創(chuàng)建它的父線程具有相同的線程,在默認(rèn)的情況下,main線程具有普通優(yōu)先級(jí)。

  • 線程讓步
    yield()方法是Thread提供的一個(gè)靜態(tài)方法,可以讓當(dāng)前正在執(zhí)行的線程暫停轉(zhuǎn)入就緒狀態(tài)。等待下一次的重新調(diào)度。
    實(shí)際上,當(dāng)某個(gè)線程調(diào)用了yield()方法后只有優(yōu)先級(jí)相同或者高于當(dāng)前線程的其他就緒狀態(tài)的線程才會(huì)獲得執(zhí)行的機(jī)會(huì)。

  • sleep和yield方法的區(qū)別
    1、sleep方法暫停當(dāng)前線程后,會(huì)給其他線程機(jī)會(huì)執(zhí)行,不會(huì)理會(huì)其他線程的優(yōu)先級(jí)。但是yield方法只會(huì)給優(yōu)先級(jí)相同或者更高的線程。
    2、sleep方法會(huì)將線程轉(zhuǎn)入阻塞狀態(tài),直到經(jīng)過阻塞時(shí)間才會(huì)轉(zhuǎn)入就緒狀態(tài)。而yield方法直接轉(zhuǎn)入就緒狀態(tài)。
    3、sleep方法會(huì)拋出InterruptedException異常,所以調(diào)用時(shí)需要顯示捕獲異常,yield方法不會(huì)拋出任何異常。
    4、sleep方法比yield方法具有更多的移植性,通常不依靠yield方法控制并發(fā)線程執(zhí)行。

  • 如果多個(gè)線程共同訪問1個(gè)對(duì)象中的實(shí)例變量,則有可能出現(xiàn)”非線程安全”

class SelfPrivateNum {
  private int num = 0;

  public void addI(String username) {
    try {

      if (username.equals("a")) {
        num = 100;
        System.out.println("a set over!");
        Thread.sleep(2000);
      } else {
        num = 200;
        System.out.println("b set over!");
      }
      System.out.println(username + " num=" + num);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }

}

class ThreadAA extends Thread {

  private SelfPrivateNum numRef;

  public ThreadAA(SelfPrivateNum numRef) {
    super();
    this.numRef = numRef;
  }

  @Override
  public void run() {
    super.run();
    numRef.addI("a");
  }

}

class ThreadBB extends Thread {

  private SelfPrivateNum numRef;

  public ThreadBB(SelfPrivateNum numRef) {
    super();
    this.numRef = numRef;
  }

  @Override
  public void run() {
    super.run();
    numRef.addI("b");
  }

}

public class RunUnsafe {

  public static void main(String[] args) {

    SelfPrivateNum numRef = new SelfPrivateNum();

    ThreadAA athread = new ThreadAA(numRef);
    athread.start();

    ThreadBB bthread = new ThreadBB(numRef);
    bthread.start();

  }

}
  • 同步方法:就是使用synchronized關(guān)鍵字來修飾某個(gè)方法。當(dāng)多個(gè)線程調(diào)用這個(gè)方法的時(shí),以排隊(duì)的方式進(jìn)行處理。同步方法不具有繼承性。
class SelfPrivateNum2 {
  private int num = 0;

  public synchronized void addI(String username) {
    try {

      if (username.equals("a")) {
        num = 100;
        System.out.println("a set over!");
        Thread.sleep(2000);
      } else {
        num = 200;
        System.out.println("b set over!");
      }
      System.out.println(username + " num=" + num);
    } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }

}

關(guān)鍵字synchronized取的是鎖都是對(duì)象鎖,而不是代碼或者是方法當(dāng)作鎖。當(dāng)多個(gè)線程訪問的是同一個(gè)對(duì)象的同步方法的時(shí)候是排隊(duì)的,而當(dāng)多個(gè)線程訪問多個(gè)對(duì)象的同步方法的時(shí)候運(yùn)行的順序是異步的。

  • A線程先持有object對(duì)象的鎖,B線程可以以異步的方式調(diào)用object對(duì)象總的非synchronizaed類型的方法
  • A線程先持有object對(duì)象的鎖,B線程如果調(diào)用object的synchronizaed類型的方法則需要等待,也就是同步。

  • 臟讀

為了避免數(shù)據(jù)出現(xiàn)交叉的情況,使用synchronized關(guān)鍵字來進(jìn)行同步。雖然在賦值時(shí)進(jìn)行了同步,但是可能在取值的時(shí)候出現(xiàn)臟讀(dirtyRead)的現(xiàn)象。發(fā)生臟讀的情況是在讀取實(shí)例變量時(shí)。出現(xiàn)臟讀是應(yīng)為getValue方法不是同步方法,解決方法可以定義為同步方法。

  • synchronized方法是對(duì)當(dāng)前對(duì)象進(jìn)行加鎖,而synchronized代碼塊是對(duì)某一個(gè)對(duì)象進(jìn)行加鎖。
//線程開始執(zhí)行同步代碼塊之前,必須先獲得對(duì)同步監(jiān)控器的鎖定
synchronized (Obj){
  ………
  //此處的代碼就是同步代碼塊  
}

通常使用可能被并發(fā)訪問的共享資源充當(dāng)同步監(jiān)視器。

  • 對(duì)同步監(jiān)視器釋放的情況:
    當(dāng)前線程的同步方法或代碼塊執(zhí)行結(jié)束
    當(dāng)前線程的同步方法或代碼塊中遇到break、return終止了該代碼塊、方法的繼續(xù)執(zhí)行
    當(dāng)前線程的同步方法或代碼塊中出現(xiàn)未處理的Error或Exception
    當(dāng)前線程的同步方法或代碼塊中執(zhí)行了同步監(jiān)控器對(duì)象的wait()方法
  • 以下情況不會(huì)釋放同步鎖:
    當(dāng)前線程的同步方法或代碼塊調(diào)用 Thread.sleep(),Thread.yield()方法來暫停當(dāng)前線程執(zhí)行
    當(dāng)前線程的同步方法或代碼塊時(shí),其他線程調(diào)用了該線程的suspend方法讓該線程掛起

  • LOCK鎖

Class A{
   private final ReentrantLock lock= new ReentrantLock ();
   //需要保證線程安全的方法
   public void m(){
    //加鎖
    lock.lock();
    try{  
      ……………
    }
    finally{
     lock.unlock();
    }
  }
}   

同步方法的比較
1、同步方法和同步代碼塊使用與競(jìng)爭(zhēng)資源相關(guān)的、隱式的同步監(jiān)視器,并且強(qiáng)制要求加鎖和釋放鎖要出現(xiàn)在同一個(gè)塊結(jié)構(gòu)中,而且當(dāng)獲取多個(gè)鎖的時(shí)候,他們必須按照相反的順序依次釋放。
2、Lock方法不僅可以使用與非結(jié)構(gòu)快中,還可以試圖中斷鎖和再次加鎖的功能。被Lock加鎖的代碼中還可以嵌套調(diào)用。
3、資源競(jìng)爭(zhēng)不是很激烈的情況下,Synchronized的性能要優(yōu)于ReetrantLock,但是在資源競(jìng)爭(zhēng)很激烈的情況下,Synchronized的性能會(huì)下降幾十倍。

  • Volatile關(guān)鍵字
    強(qiáng)制性從公共堆棧中(存放實(shí)例)中取得修飾的變量的值,而不是從線程的私有數(shù)據(jù)棧中取得變量的值。不能保證不會(huì)出現(xiàn)臟讀的情況,需要用關(guān)鍵字synchronized來解決。

  • ThreadLocal類
    ThreadLocal在每個(gè)線程中對(duì)該變量會(huì)創(chuàng)建一個(gè)副本,即每個(gè)線程內(nèi)部都會(huì)有一個(gè)該變量,且在線程內(nèi)部任何地方都可以使用,線程之間互不影響。ThreadLocal提供資源的共享對(duì)象!
    T get():返回此線程局部變量中當(dāng)前線程副本的值
    void remove():刪除此線程局部變量中當(dāng)前副本的值
    void set(T value):設(shè)置此線程局部變量中當(dāng)前線程副本的值

如果需要進(jìn)行多個(gè)線程之間共享資源,以達(dá)到線程之間的通信功能,就使用同步機(jī)制;如果僅僅需要隔離多個(gè)線程之間的共享沖突,可以使Threadlocal。

  • 死鎖:當(dāng)兩個(gè)線程相互等待對(duì)象釋放同步監(jiān)視器的時(shí)候就會(huì)發(fā)生死鎖。

    使用一種稱為資源排序的簡(jiǎn)單技術(shù)可以輕易避免死鎖。

  • 等待通知機(jī)制

方法wait()的作用是使當(dāng)前執(zhí)行代碼線程進(jìn)行等待,是Object類的方法,該方法用來將當(dāng)前線程置于“阻塞隊(duì)列”中,并在wait()所在的代碼處停止執(zhí)行,直到接到通知被喚醒。

在調(diào)用wait()之前,線程必須持有該對(duì)象的對(duì)象級(jí)別鎖,只能在同步方法或者是同步塊中調(diào)用此方法。在執(zhí)行wait方法后,當(dāng)前線程釋放鎖。進(jìn)入和其他線程競(jìng)爭(zhēng)重新獲得鎖。如果調(diào)用wait方法沒有持有鎖,則會(huì)拋出異常。

方法notify()用來通知那些可能等待該對(duì)象的對(duì)象鎖的其他線程,如果有多個(gè)線程等待,則由線程規(guī)劃器隨便選擇一個(gè)呈wait狀態(tài)的線程。

方法nofity()也是在同步方法或者同步塊中調(diào)用,調(diào)用前同樣要獲得對(duì)象的對(duì)象級(jí)別所,否則拋出異常。在執(zhí)行notify方法后,當(dāng)前線程不會(huì)馬上釋放該對(duì)象鎖,要等到執(zhí)行notify方法的線程將程序執(zhí)行完才能會(huì)釋放鎖。

方法notifyAll()方法可以使正在等待隊(duì)列中等待同一共享資源的”全部”線程從等待狀態(tài)退出,進(jìn)入可運(yùn)行狀態(tài)。

public class Test3 {
  //main方法中有三個(gè)等待線程,一個(gè)喚醒線程,一個(gè)喚醒線程只能喚醒一個(gè)等待線程,程序出現(xiàn)阻塞
  public static void main(String[] args) throws InterruptedException {

    Object lock = new Object();

    ThreadA a = new ThreadA(lock);
    new ThreadA(lock).start();
    new ThreadA(lock).start();
    new ThreadA(lock).start();

    Thread.sleep(1000);

    NotifyThread notifyThread = new NotifyThread(lock);
    notifyThread.start();

  }

}

class ThreadA extends Thread {
  private Object lock;

  public ThreadA(Object lock) {
    super();
    this.lock = lock;
  }

  @Override
  public void run() {
    Service service = new Service();
    service.testMethod(lock);
  }

}

class NotifyThread extends Thread {
  private Object lock;

  public NotifyThread(Object lock) {
    super();
    this.lock = lock;
  }

  @Override
  public void run() {
    synchronized (lock) {
      //notify()只能喚醒一個(gè)線程,nofiyAll()喚醒所有的等待線程
      lock.notify();
//     lock.notifyAll();
    }
  }

}

class Service {

  public void testMethod(Object lock) {
    try {
      synchronized (lock) {
        System.out.println("begin wait() ThreadName="
            + Thread.currentThread().getName());
        lock.wait();
        System.out.println(" end wait() ThreadName="
            + Thread.currentThread().getName());
      }
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }

}
  • 使用條件變量協(xié)調(diào)線程

在沒有使用synchronized關(guān)鍵字保證同步,而采用Lock的程序。Java提供了condition類來保持協(xié)調(diào)。Lock替代synchronized,Condition替代同步監(jiān)視器功能。
await: 類似于wait。
signal:?jiǎn)拘言诖薒ock對(duì)象上等待的單個(gè)線程,選擇是任意的。
signalAll:喚醒在此Lock對(duì)象上等待的所有線程,選擇是任意的。

public class Account
{
  //顯示定義Lock對(duì)象
  private final Lock lock = new ReentrantLock();
  //獲得指定Lock對(duì)象對(duì)應(yīng)的條件變量
  private final Condition cond = lock.newCondition(); 

  private String accountNo;
  private double balance;

  //標(biāo)識(shí)賬戶中是否已經(jīng)存款的旗標(biāo)
  private boolean flag = false;

  public Account(){}

  public Account(String accountNo , double balance)
  {
    this.accountNo = accountNo;
    this.balance = balance;
  }

  public void setAccountNo(String accountNo)
  {
    this.accountNo = accountNo;
  }
  public String getAccountNo()
  {
     return this.accountNo;
  }

  public double getBalance()
  {
     return this.balance;
  }
  public void draw(double drawAmount)
  {
    //加鎖
    lock.lock();
    try
    {
      //如果賬戶中還沒有存入存款,該線程等待
      while(!flag)
      {
        cond.await();
      }
        //執(zhí)行取錢操作
        System.out.println(Thread.currentThread().getName() + 
          " 取錢:" + drawAmount);
        balance -= drawAmount;
        System.out.println("賬戶余額為:" + balance);
        //將標(biāo)識(shí)是否成功存入存款的旗標(biāo)設(shè)為false
        flag = false;
        //喚醒該Lock對(duì)象對(duì)應(yīng)的其他線程
        cond.signalAll();
    }
    catch (InterruptedException ex)
    {
      ex.printStackTrace();
    }
    //使用finally塊來確保釋放鎖
    finally
    {
      lock.unlock();
    }
  }
  public void deposit(double depositAmount)
  {
    lock.lock();
    try
    {
      //如果賬戶中已經(jīng)存入了存款,該線程等待
      while(flag)
      {
        cond.await();        
      }

        //執(zhí)行存款操作
        System.out.println(Thread.currentThread().getName() + 
          " 存款:" + depositAmount);
        balance += depositAmount;
        System.out.println("賬戶余額為:" + balance);
        //將標(biāo)識(shí)是否成功存入存款的旗標(biāo)設(shè)為true
        flag = true;
        //喚醒該Lock對(duì)象對(duì)應(yīng)的其他線程
        cond.signalAll();
    }
    catch (InterruptedException ex)
    {
      ex.printStackTrace();
    }
    //使用finally塊來確保釋放鎖
    finally
    {
      lock.unlock();
    }
  }

  public int hashCode()
  {
    return accountNo.hashCode();
  }
  public boolean equals(Object obj)
  {
    if (obj != null && obj.getClass() == Account.class)
    {
      Account target = (Account)obj;
      return target.getAccountNo().equals(accountNo);
    }
    return false;
  }
}

使用notify()/notifyAll()方法進(jìn)行通知時(shí),被通知的線程卻是JVM隨機(jī)選擇的。當(dāng)notifyAll()通知所有WAITING線程,沒有選擇權(quán),會(huì)出現(xiàn)相當(dāng)大的效率問題。但是ReentrantLock結(jié)合Condition類可以”選擇性通知”。Condition可以實(shí)現(xiàn)喚醒部分指定線程,這樣有助于程序運(yùn)行的效率。

  • Callable和Future

從JDK1.5之后,Java提供了Callable接口,實(shí)際上就是Runnable接口的增強(qiáng)版。提供call方法作為線程執(zhí)行體,但是功能更加強(qiáng)大。
Callable接口不是Runnable接口,不能直接作為Thread的target,有返回值得call方法也不能直接運(yùn)行。這里需要一個(gè)包裝器Future。

import java.util.concurrent.*;

class RtnThread implements Callable<Integer>
{
  //實(shí)現(xiàn)call方法,作為線程執(zhí)行體
  public Integer call()
  {
    int sum = 0;
    int i=0;
    for ( ; i < 10 ; i++ )
    {
      System.out.println(Thread.currentThread().getName()+ " 的循環(huán)變量i的值:" + i); 
      sum+=i;
    }
    //call()方法可以有返回值

    return sum;
  }
} 

public class CallableTest
{
  public static void main(String[] args) 
  {
    //創(chuàng)建Callable對(duì)象
    RtnThread rt = new RtnThread();
    //使用FutureTask來包裝Callable對(duì)象
    FutureTask<Integer> task = new FutureTask<Integer>(rt);
    for (int i = 0 ; i < 10 ; i++)
    {
      System.out.println(Thread.currentThread().getName()
        + " 的循環(huán)變量i的值:" + i);
      if (i == 5)
      {
        //實(shí)質(zhì)還是以Callable對(duì)象來創(chuàng)建、并啟動(dòng)線程
        new Thread(task , "有返回值的線程").start();
      }
    }
    try
    {
      //獲取線程返回值
      System.out.println("子線程的返回值:" + task.get());          
    }
    catch (Exception ex)
    {
      ex.printStackTrace();
    }
  }
}
  • 線程池
import java.util.concurrent.*;

//實(shí)現(xiàn)Runnable接口來定義一個(gè)簡(jiǎn)單的
class TestThread implements Runnable
{
  public void run()
  {
    for (int i = 0; i < 10 ; i++ )
    {
      System.out.println(Thread.currentThread().getName()
        + "的i值為:" + i);
    }
  }
}

public class ThreadPoolTest
{
  public static void main(String[] args) 
  {
    //創(chuàng)建一個(gè)具有固定線程數(shù)(6)的線程池
    ExecutorService pool = Executors.newFixedThreadPool(6);
    //向線程池中提交3個(gè)線程
    pool.execute(new TestThread());
    Future f1=pool.submit(new TestThread());
    Future f2=pool.submit(new TestThread());

    Future<Integer> f3=pool.submit(new RtnThread());

    try
    {
      if(f1.get()==null&&f2.get()==null&&f3.get()!=null){
        System.out.println("執(zhí)行完畢!");
        System.out.println(f3.get());

      }
      //獲取線程返回值

    }
    catch (Exception ex)
    {
      ex.printStackTrace();
    }
    //關(guān)閉線程池
    pool.shutdown();
  }
}

更多java相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Java進(jìn)程與線程操作技巧總結(jié)》、《Java數(shù)據(jù)結(jié)構(gòu)與算法教程》、《Java操作DOM節(jié)點(diǎn)技巧總結(jié)》、《Java文件與目錄操作技巧匯總》和《Java緩存操作技巧匯總

希望本文所述對(duì)大家java程序設(shè)計(jì)有所幫助。

相關(guān)文章

  • 淺析Java如何優(yōu)雅的設(shè)計(jì)接口狀態(tài)碼和異常

    淺析Java如何優(yōu)雅的設(shè)計(jì)接口狀態(tài)碼和異常

    HTTP協(xié)議里定義了一系列的狀態(tài)碼用來表明請(qǐng)求的狀態(tài),如常用的200表示請(qǐng)求正常,404表示請(qǐng)求的資源不存在,所以本文就來和大家討論一下如何優(yōu)雅的設(shè)計(jì)接口狀態(tài)碼和異常,感興趣的可以了解下
    2024-03-03
  • SpringBoot整合Druid數(shù)據(jù)源的方法實(shí)現(xiàn)

    SpringBoot整合Druid數(shù)據(jù)源的方法實(shí)現(xiàn)

    Druid是阿里開發(fā)的一款開源的數(shù)據(jù)源,被很多人認(rèn)為是Java語(yǔ)言中最好的數(shù)據(jù)庫(kù)連接池,本文主要介紹了SpringBoot整合Druid數(shù)據(jù)源的方法實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • 詳解Java中的線程讓步y(tǒng)ield()與線程休眠sleep()方法

    詳解Java中的線程讓步y(tǒng)ield()與線程休眠sleep()方法

    Java中的線程讓步會(huì)讓線程讓出優(yōu)先級(jí),而休眠則會(huì)讓線程進(jìn)入阻塞狀態(tài)等待被喚醒,這里我們對(duì)比線程等待的wait()方法,來詳解Java中的線程讓步y(tǒng)ield()與線程休眠sleep()方法
    2016-07-07
  • MAC上IntelliJ IDEA的svn無法保存密碼解決方案

    MAC上IntelliJ IDEA的svn無法保存密碼解決方案

    今天小編就為大家分享一篇關(guān)于MAC上IntelliJ IDEA的svn無法保存密碼解決方案,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2018-10-10
  • Java實(shí)現(xiàn)UTF-8編碼與解碼方式

    Java實(shí)現(xiàn)UTF-8編碼與解碼方式

    這篇文章主要介紹了Java實(shí)現(xiàn)UTF-8編碼與解碼方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • SpringBoot webSocket實(shí)現(xiàn)發(fā)送廣播、點(diǎn)對(duì)點(diǎn)消息和Android接收

    SpringBoot webSocket實(shí)現(xiàn)發(fā)送廣播、點(diǎn)對(duì)點(diǎn)消息和Android接收

    這篇文章主要介紹了SpringBoot webSocket實(shí)現(xiàn)發(fā)送廣播、點(diǎn)對(duì)點(diǎn)消息和Android接收,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2017-03-03
  • Java編程實(shí)現(xiàn)基于TCP協(xié)議的Socket聊天室示例

    Java編程實(shí)現(xiàn)基于TCP協(xié)議的Socket聊天室示例

    這篇文章主要介紹了Java編程實(shí)現(xiàn)基于TCP協(xié)議的Socket聊天室,結(jié)合實(shí)例形式詳細(xì)分析了java基于TCP協(xié)議的Socket聊天室客戶端與服務(wù)器端相關(guān)實(shí)現(xiàn)與使用技巧,需要的朋友可以參考下
    2018-01-01
  • Spring中Bean的生命周期及實(shí)例化操作詳解

    Spring中Bean的生命周期及實(shí)例化操作詳解

    這篇文章主要介紹了Spring中Bean的生命周期及實(shí)例化操作詳解,spring的核心思想之一IOC就是通過IOC容器對(duì)Bean的創(chuàng)建和各個(gè)bean之間的依賴關(guān)系進(jìn)行操作,今天就來和大家分享一下bean的生命周期相關(guān)知識(shí)點(diǎn),需要的朋友可以參考下
    2023-08-08
  • Java實(shí)現(xiàn)多叉樹和二叉樹之間的互轉(zhuǎn)

    Java實(shí)現(xiàn)多叉樹和二叉樹之間的互轉(zhuǎn)

    本文主要介紹了Java實(shí)現(xiàn)多叉樹和二叉樹之間的互轉(zhuǎn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • java使用EasyExcel實(shí)現(xiàn)Sheet的復(fù)制與填充

    java使用EasyExcel實(shí)現(xiàn)Sheet的復(fù)制與填充

    EasyExcel是一個(gè)非常有用的工具,它提供了強(qiáng)大的模板填充功能,可以輕松解決各種業(yè)務(wù)需求,本文主要為大家介紹了如何使用EasyExcel實(shí)現(xiàn)模板Sheet復(fù)制與填充,需要的可以參考下
    2023-10-10

最新評(píng)論