最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java多線程編程詳細(xì)解釋

 更新時間:2021年11月05日 11:16:05   作者:山高我為峰  
這篇文章主要介紹了java多線程編程實(shí)例,分享了幾則多線程的實(shí)例代碼,具有一定參考價值,加深多線程編程的理解還是很有幫助的,需要的朋友可以參考下。

一、多線程的優(yōu)缺點(diǎn)

多線程的優(yōu)點(diǎn):

1)資源利用率更好

2)程序設(shè)計在某些情況下更簡單

3)程序響應(yīng)更快

多線程的代價:

1)設(shè)計更復(fù)雜

雖然有一些多線程應(yīng)用程序比單線程的應(yīng)用程序要簡單,但其他的一般都更復(fù)雜。在多線程訪問共享數(shù)據(jù)的時候,這部分代碼需要特別的注意。線程之間的交互往往非常復(fù)雜。不正確的線程同步產(chǎn)生的錯誤非常難以被發(fā)現(xiàn),并且重現(xiàn)以修復(fù)。

2)上下文切換的開銷

當(dāng)CPU從執(zhí)行一個線程切換到執(zhí)行另外一個線程的時候,它需要先存儲當(dāng)前線程的本地的數(shù)據(jù),程序指針等,然后載入另一個線程的本地數(shù)據(jù),程序指針等,最后才開始執(zhí)行。這種切換稱為“上下文切換”(“context switch”)。CPU會在一個上下文中執(zhí)行一個線程,然后切換到另外一個上下文中執(zhí)行另外一個線程。上下文切換并不廉價。如果沒有必要,應(yīng)該減少上下文切換的發(fā)生。

二、創(chuàng)建java多線程

1、創(chuàng)建Thread的子類

創(chuàng)建Thread子類的一個實(shí)例并重寫run方法,run方法會在調(diào)用start()方法之后被執(zhí)行。例子如下:

public class MyThread extends Thread {
   public void run(){
     System.out.println("MyThread running");
   }
}
MyThread myThread = new MyThread();
myTread.start();

也可以如下創(chuàng)建一個Thread的匿名子類:

Thread thread = new Thread(){
   public void run(){
     System.out.println("Thread Running");
   }
};
thread.start();

2、實(shí)現(xiàn)Runnable接口

第二種編寫線程執(zhí)行代碼的方式是新建一個實(shí)現(xiàn)了java.lang.Runnable接口的類的實(shí)例,實(shí)例中的方法可以被線程調(diào)用。下面給出例子:

public class MyRunnable implements Runnable {
   public void run(){
    System.out.println("MyRunnable running");
   }
}
Thread thread = new Thread(new MyRunnable());
thread.start();

同樣,也可以創(chuàng)建一個實(shí)現(xiàn)了Runnable接口的匿名類,如下所示:

Runnable myRunnable = new Runnable(){
   public void run(){
     System.out.println("Runnable running");
   }
}
Thread thread = new Thread(myRunnable);
thread.start();

三、線程安全

在同一程序中運(yùn)行多個線程本身不會導(dǎo)致問題,問題在于多個線程訪問了相同的資源。如同一內(nèi)存區(qū)(變量,數(shù)組,或?qū)ο螅⑾到y(tǒng)(數(shù)據(jù)庫,web services等)或文件。實(shí)際上,這些問題只有在一或多個線程向這些資源做了寫操作時才有可能發(fā)生,只要資源沒有發(fā)生變化,多個線程讀取相同的資源就是安全的。

當(dāng)兩個線程競爭同一資源時,如果對資源的訪問順序敏感,就稱存在競態(tài)條件。導(dǎo)致競態(tài)條件發(fā)生的代碼區(qū)稱作臨界區(qū)。

如果一個資源的創(chuàng)建,使用,銷毀都在同一個線程內(nèi)完成,且永遠(yuǎn)不會脫離該線程的控制,則該資源的使用就是線程安全的。

四、java同步塊

Java中的同步塊用synchronized標(biāo)記。同步塊在Java中是同步在某個對象上。所有同步在一個對象上的同步塊在同時只能被一個線程進(jìn)入并執(zhí)行操作。所有其他等待進(jìn)入該同步塊的線程將被阻塞,直到執(zhí)行該同步塊中的線程退出。

有四種不同的同步塊:

實(shí)例方法靜態(tài)方法實(shí)例方法中的同步塊靜態(tài)方法中的同步塊

實(shí)例方法同步:

 public synchronized void add(int value){
this.count += value;
 }

Java實(shí)例方法同步是同步在擁有該方法的對象上。這樣,每個實(shí)例其方法同步都同步在不同的對象上,即該方法所屬的實(shí)例。只有一個線程能夠在實(shí)例方法同步塊中運(yùn)行。如果有多個實(shí)例存在,那么一個線程一次可以在一個實(shí)例同步塊中執(zhí)行操作。一個實(shí)例一個線程。

靜態(tài)方法同步:

public static synchronized void add(int value){
 count += value;
 }

靜態(tài)方法的同步是指同步在該方法所在的類對象上。因?yàn)樵贘ava虛擬機(jī)中一個類只能對應(yīng)一個類對象,所以同時只允許一個線程執(zhí)行同一個類中的靜態(tài)同步方法。

實(shí)例方法中的同步塊:

public void add(int value){
    synchronized(this){
       this.count += value;
    }
  }

注意Java同步塊構(gòu)造器用括號將對象括起來。在上例中,使用了“this”,即為調(diào)用add方法的實(shí)例本身。在同步構(gòu)造器中用括號括起來的對象叫做監(jiān)視器對象。上述代碼使用監(jiān)視器對象同步,同步實(shí)例方法使用調(diào)用方法本身的實(shí)例作為監(jiān)視器對象。一次只有一個線程能夠在同步于同一個監(jiān)視器對象的Java方法內(nèi)執(zhí)行。

下面兩個例子都同步他們所調(diào)用的實(shí)例對象上,因此他們在同步的執(zhí)行效果上是等效的。

public class MyClass {
   public synchronized void log1(String msg1, String msg2){
      log.writeln(msg1);
      log.writeln(msg2);
   }
   public void log2(String msg1, String msg2){
      synchronized(this){
         log.writeln(msg1);
         log.writeln(msg2);
      }
   }
 }

靜態(tài)方法中的同步塊:

public class MyClass {
    public static synchronized void log1(String msg1, String msg2){
       log.writeln(msg1);
       log.writeln(msg2);
    }
    public static void log2(String msg1, String msg2){
       synchronized(MyClass.class){
          log.writeln(msg1);
          log.writeln(msg2);
       }
    }
  }

這兩個方法不允許同時被線程訪問。如果第二個同步塊不是同步在MyClass.class這個對象上。那么這兩個方法可以同時被線程訪問。

五、java線程通信

線程通信的目標(biāo)是使線程間能夠互相發(fā)送信號。另一方面,線程通信使線程能夠等待其他線程的信號。

Java有一個內(nèi)建的等待機(jī)制來允許線程在等待信號的時候變?yōu)榉沁\(yùn)行狀態(tài)。java.lang.Object 類定義了三個方法,wait()、notify()和notifyAll()來實(shí)現(xiàn)這個等待機(jī)制。

一個線程一旦調(diào)用了任意對象的wait()方法,就會變?yōu)榉沁\(yùn)行狀態(tài),直到另一個線程調(diào)用了同一個對象的notify()方法。為了調(diào)用wait()或者notify(),線程必須先獲得那個對象的鎖。也就是說,線程必須在同步塊里調(diào)用wait()或者notify()。

以下為一個使用了wait()和notify()實(shí)現(xiàn)的線程間通信的共享對象:

public class MyWaitNotify{
  MonitorObject myMonitorObject = new MonitorObject();
  boolean wasSignalled = false;
  public void doWait(){
    synchronized(myMonitorObject){
      while(!wasSignalled){
        try{
          myMonitorObject.wait();
         } catch(InterruptedException e){...}
      }
      //clear signal and continue running.
      wasSignalled = false;
    }
  }
  public void doNotify(){
    synchronized(myMonitorObject){
      wasSignalled = true;
      myMonitorObject.notify();
    }
  }
}

注意以下幾點(diǎn):

1、不管是等待線程還是喚醒線程都在同步塊里調(diào)用wait()和notify()。這是強(qiáng)制性的!一個線程如果沒有持有對象鎖,將不能調(diào)用wait(),notify()或者notifyAll()。否則,會拋出IllegalMonitorStateException異常。

2、一旦線程調(diào)用了wait()方法,它就釋放了所持有的監(jiān)視器對象上的鎖。這將允許其他線程也可以調(diào)用wait()或者notify()。

3、為了避免丟失信號,必須把它們保存在信號類里。如上面的wasSignalled變量。

4、假喚醒:由于莫名其妙的原因,線程有可能在沒有調(diào)用過notify()和notifyAll()的情況下醒來。這就是所謂的假喚醒(spurious wakeups)。為了防止假喚醒,保存信號的成員變量將在一個while循環(huán)里接受檢查,而不是在if表達(dá)式里。這樣的一個while循環(huán)叫做自旋鎖。

5、不要在字符串常量或全局對象中調(diào)用wait()。即上面MonitorObject不能是字符串常量或是全局對象。每一個MyWaitNotify的實(shí)例都擁有一個屬于自己的監(jiān)視器對象,而不是在空字符串上調(diào)用wait()/notify()。

六、java中的鎖

自Java 5開始,java.util.concurrent.locks包中包含了一些鎖的實(shí)現(xiàn),因此你不用去實(shí)現(xiàn)自己的鎖了。

常用的一些鎖:

java.util.concurrent.locks.Lock;

java.util.concurrent.locks.ReentrantLock;

java.util.concurrent.locks.ReadWriteLock;

java.util.concurrent.locks.ReentrantReadWriteLock;

一個可重入鎖(reentrant lock)的簡單實(shí)現(xiàn):

public class Lock {
    boolean isLocked = false;
    Thread  lockedBy = null;
    int lockedCount = 0;
    public synchronized void lock() throws InterruptedException{
        Thread callingThread = Thread.currentThread();
        while(isLocked && lockedBy != callingThread){
            wait();
        }
        isLocked = true;
        lockedCount++;
        lockedBy = callingThread;
    }
    public synchronized void unlock(){
        if(Thread.currentThread() == this.lockedBy){
            lockedCount--;
            if(lockedCount == 0){
                isLocked = false;
                notify();
            }
        }
    }
}

注意的一點(diǎn):在finally語句中調(diào)用unlock()

lock.lock();
try{
    //do critical section code, which may throw exception
} finally {
    lock.unlock();
}

七、java中其他同步方法

信號量(Semaphore):java.util.concurrent.Semaphore

阻塞隊(duì)列(Blocking Queue):java.util.concurrent.BlockingQueue

public class BlockingQueue {
    private List queue = new LinkedList();
    private int limit = 10;
    public BlockingQueue(int limit) {
        this.limit = limit;
    }
    public synchronized void enqueue(Object item) throws InterruptedException {
        while (this.queue.size() == this.limit) {
            wait();
        }
        if (this.queue.size() == 0) {
            notifyAll();
        }
        this.queue.add(item);
    }
    public synchronized Object dequeue() throws InterruptedException {
        while (this.queue.size() == 0) {
            wait();
        }
        if (this.queue.size() == this.limit) {
            notifyAll();
        }
        return this.queue.remove(0);
    }
}

八、java中的線程池

Java通過Executors提供四種線程池,分別為:

newCachedThreadPool

創(chuàng)建一個可緩存的線程池。如果線程池的大小超過了處理任務(wù)所需要的線程,那么就會回收部分空閑(60秒不執(zhí)行任務(wù))的線程,當(dāng)任務(wù)數(shù)增加時,此線程池又可以智能的添加新線程來處理任務(wù)。此線程池不會對線程池大小做限制,線程池大小完全依賴于操作系統(tǒng)(或者說JVM)能夠創(chuàng)建的最大線程大小。

newFixedThreadPool

創(chuàng)建固定大小的線程池。每次提交一個任務(wù)就創(chuàng)建一個線程,直到線程達(dá)到線程池的最大大小。線程池的大小一旦達(dá)到最大值就會保持不變,如果某個線程因?yàn)閳?zhí)行異常而結(jié)束,那么線程池會補(bǔ)充一個新線程。

newScheduledThreadPool

創(chuàng)建一個大小無限制的線程池。此線程池支持定時以及周期性執(zhí)行任務(wù)。

newSingleThreadExecutor

創(chuàng)建一個單線程的線程池。此線程池支持定時以及周期性執(zhí)行任務(wù)。這個線程池只有一個線程在工作,也就是相當(dāng)于單線程串行執(zhí)行所有任務(wù)。如果這個唯一的線程因?yàn)楫惓=Y(jié)束,那么會有一個新的線程來替代它。此線程池保證所有任務(wù)的執(zhí)行順序按照任務(wù)的提交順序執(zhí)行。

線程池簡單用法:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
    public static void main(String[] args) {
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            final int index = i;
            cachedThreadPool.execute(new Runnable() {
                public void run() {
                    System.out.println(index);
                }
            });
        }
    }
}

參考:

http://tutorials.jenkov.com/java-concurrency/index.html

http://www.fzitv.net/article/214633.htm

Java線程池的分析和使用://www.fzitv.net/article/227397.htm

總結(jié)

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

  • SpringBoot?實(shí)現(xiàn)CAS?Server統(tǒng)一登錄認(rèn)證的詳細(xì)步驟

    SpringBoot?實(shí)現(xiàn)CAS?Server統(tǒng)一登錄認(rèn)證的詳細(xì)步驟

    ??CAS(Central?Authentication?Service)中心授權(quán)服務(wù),是一個開源項(xiàng)目,目的在于為Web應(yīng)用系統(tǒng)提供一種可靠的單點(diǎn)登錄,這篇文章主要介紹了SpringBoot?實(shí)現(xiàn)CAS?Server統(tǒng)一登錄認(rèn)證,需要的朋友可以參考下
    2024-02-02
  • Java JVM中線程狀態(tài)詳解

    Java JVM中線程狀態(tài)詳解

    這篇文章主要介紹了Java JVM中線程狀態(tài)詳解,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,感興趣的朋友可以參考一下
    2022-09-09
  • Spring Security實(shí)現(xiàn)多次登錄失敗后賬戶鎖定功能

    Spring Security實(shí)現(xiàn)多次登錄失敗后賬戶鎖定功能

    當(dāng)用戶多次登錄失敗的時候,我們應(yīng)該將賬戶鎖定,等待一定的時間之后才能再次進(jìn)行登錄操作。今天小編給大家分享Spring Security實(shí)現(xiàn)多次登錄失敗后賬戶鎖定功能,感興趣的朋友一起看看吧
    2019-11-11
  • Spring框架配置java web實(shí)現(xiàn)實(shí)例化

    Spring框架配置java web實(shí)現(xiàn)實(shí)例化

    這篇文章主要介紹了Spring框架配置java web實(shí)現(xiàn)實(shí)例化,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-04-04
  • Spring MVC打印@RequestBody、@Response日志的方法

    Spring MVC打印@RequestBody、@Response日志的方法

    這篇文章主要介紹了Spring MVC打印@RequestBody、@Response日志的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-02-02
  • 第三方包jintellitype實(shí)現(xiàn)Java設(shè)置全局熱鍵

    第三方包jintellitype實(shí)現(xiàn)Java設(shè)置全局熱鍵

    本文主要介紹了,在java中使用第三方插件包jintellitype來實(shí)現(xiàn)全局熱鍵,非常的簡單,但是很實(shí)用,有需要的朋友可以參考下,歡迎一起來參與改進(jìn)此項(xiàng)目
    2014-09-09
  • Spring使用IOC與DI實(shí)現(xiàn)完全注解開發(fā)

    Spring使用IOC與DI實(shí)現(xiàn)完全注解開發(fā)

    IOC也是Spring的核心之一了,之前學(xué)的時候是采用xml配置文件的方式去實(shí)現(xiàn)的,后來其中也多少穿插了幾個注解,但是沒有說完全采用注解實(shí)現(xiàn)。那么這篇文章就和大家分享一下,全部采用注解來實(shí)現(xiàn)IOC + DI
    2022-09-09
  • Java中的String.valueOf()和toString()方法區(qū)別小結(jié)

    Java中的String.valueOf()和toString()方法區(qū)別小結(jié)

    字符串操作是開發(fā)者日常編程任務(wù)中不可或缺的一部分,轉(zhuǎn)換為字符串是一種常見需求,其中最常見的就是String.valueOf()和toString()方法,本文主要介紹了Java中的String.valueOf()和toString()方法區(qū)別小結(jié),感興趣的可以了解一下
    2025-04-04
  • Java高效實(shí)現(xiàn)電商產(chǎn)品排序?qū)崙?zhàn)

    Java高效實(shí)現(xiàn)電商產(chǎn)品排序?qū)崙?zhàn)

    這篇文章主要為大家介紹了Java高效實(shí)現(xiàn)電商產(chǎn)品排序?qū)崙?zhàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • Java設(shè)計模式之裝飾模式詳解

    Java設(shè)計模式之裝飾模式詳解

    這篇文章主要介紹了Java設(shè)計模式之裝飾模式詳解,文中有非常詳細(xì)的代碼示例,對正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-04-04

最新評論

四川省| 行唐县| 措美县| 昌吉市| 宁安市| 泰宁县| 乌苏市| 龙岩市| 东方市| 杭锦后旗| 桦川县| 上高县| 汾阳市| 常山县| 枣强县| 南皮县| 彰化县| 桂东县| 菏泽市| 洱源县| 扎赉特旗| 许昌县| 手游| 巴青县| 武隆县| 沙河市| 三门峡市| 双牌县| 微山县| 临江市| 海安县| 龙州县| 西华县| 美姑县| 三亚市| 景洪市| 恭城| 延长县| 同德县| 阿坝| 阜康市|