黄色网址大全免费-黄色网址你懂得-黄色网址你懂的-黄色网址有那些-免费超爽视频-免费大片黄国产在线观看

專(zhuān)注Java教育14年 全國(guó)咨詢(xún)/投訴熱線:400-8080-105
動(dòng)力節(jié)點(diǎn)LOGO圖
始于2009,口口相傳的Java黃埔軍校
首頁(yè) hot資訊 Java多線程并發(fā)編程

Java多線程并發(fā)編程

更新時(shí)間:2021-05-17 15:54:59 來(lái)源:動(dòng)力節(jié)點(diǎn) 瀏覽1894次

1. 為什么要用多線程

小編相信所有的東西都是以實(shí)際使用價(jià)值而去學(xué)習(xí)的,沒(méi)有實(shí)際價(jià)值的學(xué)習(xí),學(xué)了沒(méi)用,沒(méi)用就不會(huì)學(xué)的好。

多線程也是一樣,以前學(xué)習(xí)Java并沒(méi)有覺(jué)得多線程有多了不起,不用多線程我一樣可以開(kāi)發(fā),但是做的久了你就會(huì)發(fā)現(xiàn),一些東西必須用多線程去解決。

明白并發(fā)編程是通過(guò)cpu調(diào)度算法,讓用戶(hù)看上去同時(shí)執(zhí)行,實(shí)際上從cpu操作層面不是真正的同時(shí)。

多線程安全問(wèn)題原因是在cpu執(zhí)行多線程時(shí),在執(zhí)行的過(guò)程中可能隨時(shí)切換到其他的線程上執(zhí)行。

2. 創(chuàng)建線程的方式

(1)繼承Thread類(lèi)

用戶(hù)的線程類(lèi)只須繼承Thread類(lèi)并重寫(xiě)其run()方法即可,通過(guò)調(diào)用用戶(hù)線程類(lèi)的start()方法即可啟動(dòng)用戶(hù)線程

class MyThread extends Thread{
  public void run(){

  }
}

public class TestThread{
  public static void main(String[] args){
      MyThread thread = new MyThread();//創(chuàng)建用戶(hù)線程對(duì)象
      thread.start();//啟動(dòng)用戶(hù)線程
      thread.run();//主線程調(diào)用用戶(hù)線程對(duì)象的run()方法
  }
}

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

當(dāng)使用Thread(Runnable thread)方式創(chuàng)建線程對(duì)象時(shí),須為該方法傳遞一個(gè)實(shí)現(xiàn)了Runnable接口的對(duì)象,這樣創(chuàng)建的線程將調(diào)用實(shí)現(xiàn)Runnable接口的對(duì)象的run()方法

public class TestThread{
  public static void main(String[] args){
      Mythread mt = new Mythread();
      Thread t = new Thread(mt);//創(chuàng)建用戶(hù)線程
       t.start();//啟動(dòng)用戶(hù)線程
  }
}
class Mythread implements Runnable{
    public void run(){

    }
}

至于哪個(gè)好,不用說(shuō)肯定是后者好,因?yàn)閷?shí)現(xiàn)接口的方式比繼承類(lèi)的方式更靈活,也能減少程序之間的耦合度,面向接口編程也是設(shè)計(jì)模式6大原則的核心。

3. 線程的生命周期

4. 線程安全

指在并發(fā)的情況之下,該代碼經(jīng)過(guò)多線程使用,線程的調(diào)度順序不影響任何結(jié)果。

線程安全也是有幾個(gè)級(jí)別的:

(1)不可變

像String、Integer、Long這些,都是final類(lèi)型的類(lèi),任何一個(gè)線程都改變不了它們的值,要改變除非新創(chuàng)建一個(gè),因此這些不可變對(duì)象不需要任何同步手段就可以直接在多線程環(huán)境下使用

(2)絕對(duì)線程安全

不管運(yùn)行時(shí)環(huán)境如何,調(diào)用者都不需要額外的同步措施。要做到這一點(diǎn)通常需要付出許多額外的代價(jià),Java中標(biāo)注自己是線程安全的類(lèi),實(shí)際上絕大多數(shù)都不是線程安全的,不過(guò)絕對(duì)線程安全的類(lèi),Java中也有,比方說(shuō)CopyOnWriteArrayList、CopyOnWriteArraySet

(3)相對(duì)線程安全

相對(duì)線程安全也就是我們通常意義上所說(shuō)的線程安全,像Vector這種,add、remove方法都是原子操作,不會(huì)被打斷,但也僅限于此,如果有個(gè)線程在遍歷某個(gè)Vector、有個(gè)線程同時(shí)在add這個(gè)Vector,99%的情況下都會(huì)出現(xiàn)ConcurrentModificationException,也就是fail-fast機(jī)制。

(4)線程非安全

這個(gè)就沒(méi)什么好說(shuō)的了,ArrayList、LinkedList、HashMap等都是線程非安全的類(lèi)

5. 鎖

死鎖:學(xué)習(xí)操作系統(tǒng)時(shí)給的定義:死鎖是指兩個(gè)或兩個(gè)以上的進(jìn)程在執(zhí)行過(guò)程中,由于競(jìng)爭(zhēng)資源或者由于彼此通信而造成的一種阻塞的現(xiàn)象,若無(wú)外力作用,它們都將無(wú)法推進(jìn)下去。此時(shí)稱(chēng)系統(tǒng)處于死鎖狀態(tài)或系統(tǒng)產(chǎn)生了死鎖,這些永遠(yuǎn)在互相等待的進(jìn)程稱(chēng)為死鎖進(jìn)程。

樂(lè)觀鎖:就像它的名字一樣,對(duì)于并發(fā)間操作產(chǎn)生的線程安全問(wèn)題持樂(lè)觀狀態(tài),樂(lè)觀鎖認(rèn)為競(jìng)爭(zhēng)不總是會(huì)發(fā)生,因此它不需要持有鎖,將比較-設(shè)置這兩個(gè)動(dòng)作作為一個(gè)原子操作嘗試去修改內(nèi)存中的變量,如果失敗則表示發(fā)生沖突,那么就應(yīng)該有相應(yīng)的重試邏輯。

悲觀鎖:還是像它的名字一樣,對(duì)于并發(fā)間操作產(chǎn)生的線程安全問(wèn)題持悲觀狀態(tài),悲觀鎖認(rèn)為競(jìng)爭(zhēng)總是會(huì)發(fā)生,因此每次對(duì)某資源進(jìn)行操作時(shí),都會(huì)持有一個(gè)獨(dú)占的鎖,就像synchronized,不管三七二十一,直接上了鎖就操作資源了。

6. 線程間操作

(1)線程間的通信

多個(gè)線程處理同一個(gè)資源,需要線程間通信解決線程對(duì)資源的占用,避免對(duì)同一資源爭(zhēng)奪。及引入等待喚醒機(jī)制(wait(),notify())

(a)wait()方法:線程調(diào)用wait()方法,釋放它對(duì)鎖的擁有權(quán),然后等待另外的線程來(lái)通知它(通知的方式是notify()或者notifyAll()方法),這樣它才能重新獲得鎖的擁有權(quán)和恢復(fù)執(zhí)行。

要確保調(diào)用wait()方法的時(shí)候擁有鎖,即,wait()方法的調(diào)用必須放在synchronized方法或synchronized塊中。

(b)notify()方法:notify()方法會(huì)喚醒一個(gè)等待當(dāng)前對(duì)象的鎖的線程。喚醒在此對(duì)象監(jiān)視器上等待的單個(gè)線程。

(c)notifAll()方法:notifyAll()方法會(huì)喚醒在此對(duì)象監(jiān)視器上等待的所有線程。

(2)兩個(gè)線程之間共享數(shù)據(jù):網(wǎng)上給出的兩種方式

方式一:當(dāng)每個(gè)線程執(zhí)行的代碼相同時(shí),可以使用同一個(gè)Runnable對(duì)象

public class MultiThreadShareData {
    public static void main(String[] args) {
        ShareData task = new ShareData(); //一個(gè)類(lèi)實(shí)現(xiàn)了Runnable接口
        for(int i = 0; i < 4; i ++) {   //四個(gè)線程來(lái)賣(mài)票
            new Thread(task).start();
        }
    }
}
class ShareData implements Runnable {
    private int data = 100;
    @Override
    public void run() { //賣(mài)票,每次一個(gè)線程進(jìn)來(lái),先判斷票數(shù)是否大于0
//      while(data > 0) {
            synchronized(this) {
                if(data > 0) {
                    System.out.println(Thread.currentThread().getName() + ": " + data);
                    data--;
                }
            }
//      }
    }
}

方式二:若每個(gè)線程執(zhí)行任務(wù)不同,可以將兩個(gè)任務(wù)方法放到一個(gè)類(lèi)中,然后將data也放在這個(gè)類(lèi)中,然后傳到不同的Runnable中,即可完成數(shù)據(jù)的共享

public class MultiThreadShareData {
    public static void main(String[] args) {
        ShareData task = new ShareData(); //公共數(shù)據(jù)和任務(wù)放在task中
        for(int i = 0; i < 2; i ++) { //開(kāi)啟兩個(gè)線程增加data
            new Thread(new Runnable() {
                @Override
                public void run() {
                    task.increment();
                }
            }).start();
        }
        for(int i = 0; i < 2; i ++) { //開(kāi)啟兩個(gè)線程減少data
            new Thread(new Runnable() {
                @Override
                public void run() {
                    task.decrement();
                }
            }).start();
        }
    }
}

class ShareData /*implements Runnable*/ {
    private int data = 0;
    public synchronized void increment() { //增加data
        System.out.println(Thread.currentThread().getName() + ": before : " + data);
        data++;
        System.out.println(Thread.currentThread().getName() + ": after : " + data);
    }
    public synchronized void decrement() { //減少data
        System.out.println(Thread.currentThread().getName() + ": before : " + data);
        data--;
        System.out.println(Thread.currentThread().getName() + ": after : " + data);
    }
}

本地線程:ThreadLocal

7. 線程池

作用:避免頻繁地創(chuàng)建和銷(xiāo)毀線程,達(dá)到線程對(duì)象的重用。另外,使用線程池還可以根據(jù)項(xiàng)目靈活地控制并發(fā)的數(shù)目。

(1)ThreadPoolExecutor類(lèi)

1)ThreadPoolExecutor類(lèi)是線程池中最核心的一個(gè)類(lèi),它提供了四個(gè)構(gòu)造方法。

public class ThreadPoolExecutor extends AbstractExecutorService {
/**
*corePoolSize:核心池的大小
*maximumPoolSize:線程池最大線程數(shù)
*keepAliveTime:表示線程沒(méi)有任務(wù)執(zhí)行時(shí)最多保持多久時(shí)間會(huì)終止
*unit:參數(shù)keepAliveTime的時(shí)間單位,有7種取值,在TimeUnit類(lèi)中有7種靜態(tài)屬性
*    TimeUnit.DAYS;               //天
*    TimeUnit.HOURS;             //小時(shí)
*    TimeUnit.MINUTES;           //分鐘
*    TimeUnit.SECONDS;           //秒
*    TimeUnit.MILLISECONDS;      //毫秒
*    TimeUnit.MICROSECONDS;      //微妙
*    TimeUnit.NANOSECONDS;       //納秒
*workQueue:一個(gè)阻塞隊(duì)列,用來(lái)存儲(chǔ)等待執(zhí)行的任務(wù)
*    ArrayBlockingQueue;
*    LinkedBlockingQueue;
*    SynchronousQueue;
*threadFactory:線程工廠,主要用來(lái)創(chuàng)建線程
*handler:表示當(dāng)拒絕處理任務(wù)時(shí)的策略,有以下四種取值
*    ThreadPoolExecutor.AbortPolicy:丟棄任務(wù)并拋出RejectedExecutionException異常。
*    ThreadPoolExecutor.DiscardPolicy:也是丟棄任務(wù),但是不拋出異常。
*    ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊(duì)列最前面的任務(wù),然后重新嘗試執(zhí)行任務(wù)(重復(fù)此過(guò)程)
*    ThreadPoolExecutor.CallerRunsPolicy:由調(diào)用線程處理該任務(wù)
*/
    .....
    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
            BlockingQueue<Runnable> workQueue);

    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
            BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory);

    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
            BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler);

    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
        BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler);
    ...
}

2)ThreadPoolExecutor的其他方法

a)execute()方法實(shí)際上是Executor中聲明的方法,在ThreadPoolExecutor進(jìn)行了具體的實(shí)現(xiàn),這個(gè)方法是ThreadPoolExecutor的核心方法,通過(guò)這個(gè)方法可以向線程池提交一個(gè)任務(wù),交由線程池去執(zhí)行。

b)submit()方法是在ExecutorService中聲明的方法,在AbstractExecutorService就已經(jīng)有了具體的實(shí)現(xiàn),在ThreadPoolExecutor中并沒(méi)有對(duì)其進(jìn)行重寫(xiě),這個(gè)方法也是用來(lái)向線程池提交任務(wù)的,但是它和execute()方法不同,它能夠返回任務(wù)執(zhí)行的結(jié)果,去看submit()方法的實(shí)現(xiàn),會(huì)發(fā)現(xiàn)它實(shí)際上還是調(diào)用的execute()方法,只不過(guò)它利用了Future來(lái)獲取任務(wù)執(zhí)行結(jié)果

c)shutdown()和shutdownNow()是用來(lái)關(guān)閉線程池的。

d)還有很多其他的方法:比如:getQueue()、getPoolSize()、getActiveCount()、getCompletedTaskCount()等獲取與線程池相關(guān)屬性的方法,有興趣的朋友可以自行查閱API。

(2)使用示例

使用時(shí),并不提倡直接使用ThreadPoolExcutor,而是使用Executors類(lèi)中的幾個(gè)靜態(tài)方法來(lái)創(chuàng)建線程池,即

Executors.newCachedThreadPool(int  Integer.MAX_VALUE );        //創(chuàng)建一個(gè)緩沖池,緩沖池容量大小為
Executors.newSingleThreadExecutor();   //創(chuàng)建容量為1的緩沖池
Executors.newFixedThreadPool();    //創(chuàng)建固定容量大小的緩沖池

使用示例:

public class ThreadPoolTest{
    public static void main(String[] args){
        // 創(chuàng)建一個(gè)容量為5的線程池
        ExecutorService executorService = Executors.newFixedThreadPool(5);
    // 向線程池提交一個(gè)任務(wù)(其實(shí)就是通過(guò)線程池來(lái)啟動(dòng)一個(gè)線程)
    for( int i = 0;i<15;i++){
        executorService.execute(new TestRunnable());
        system.out.println("******************");
    }
        executorService.shotdown();
    }
}
class TestRunnable extends Thread{
    @override
    public void run(){
      try{
          Thread.sleep(1000*6);
    }catch(InterruptedException e){
        e.printStackTrace();
    }
}
}

(3)其他問(wèn)題

1)如果你提交任務(wù)時(shí),線程池隊(duì)列已滿(mǎn),這時(shí)會(huì)發(fā)生什么

如果你使用的LinkedBlockingQueue,也就是無(wú)界隊(duì)列的話(huà),沒(méi)關(guān)系,繼續(xù)添加任務(wù)到阻塞隊(duì)列中等待執(zhí)行,因?yàn)長(zhǎng)inkedBlockingQueue可以近乎認(rèn)為是一個(gè)無(wú)窮大的隊(duì)列,可以無(wú)限存放任務(wù);如果你使用的是有界隊(duì)列比方說(shuō)ArrayBlockingQueue的話(huà),任務(wù)首先會(huì)被添加到ArrayBlockingQueue中,ArrayBlockingQueue滿(mǎn)了,則會(huì)使用拒絕策略RejectedExecutionHandler處理滿(mǎn)了的任務(wù),默認(rèn)是AbortPolicy。

2)高并發(fā)、任務(wù)執(zhí)行時(shí)間短的業(yè)務(wù)怎樣使用線程池?并發(fā)不高、任務(wù)執(zhí)行時(shí)間長(zhǎng)的業(yè)務(wù)怎樣使用線程池?并發(fā)高、業(yè)務(wù)執(zhí)行時(shí)間長(zhǎng)的業(yè)務(wù)怎樣使用線程池?這是我在并發(fā)編程網(wǎng)上看到的一個(gè)問(wèn)題:

①高并發(fā)、任務(wù)執(zhí)行時(shí)間短的業(yè)務(wù),線程池線程數(shù)可以設(shè)置為CPU核數(shù)+1,減少線程上下文的切換

②并發(fā)不高、任務(wù)執(zhí)行時(shí)間長(zhǎng)的業(yè)務(wù)要區(qū)分開(kāi)看:

  • 假如是業(yè)務(wù)時(shí)間長(zhǎng)集中在IO操作上,也就是IO密集型的任務(wù),因?yàn)镮O操作并不占用CPU,所以不要讓所有的CPU閑下來(lái),可以加大線程池中的線程數(shù)目,讓CPU處理更多的業(yè)務(wù)
  • 假如是業(yè)務(wù)時(shí)間長(zhǎng)集中在計(jì)算操作上,也就是計(jì)算密集型任務(wù),這個(gè)就沒(méi)辦法了,和(1)一樣吧,線程池中的線程數(shù)設(shè)置得少一些,減少線程上下文的切換

③并發(fā)高、業(yè)務(wù)執(zhí)行時(shí)間長(zhǎng),解決這種類(lèi)型任務(wù)的關(guān)鍵不在于線程池而在于整體架構(gòu)的設(shè)計(jì),看看這些業(yè)務(wù)里面某些數(shù)據(jù)是否能做緩存是第一步,增加服務(wù)器是第二步,至于線程池的設(shè)置,設(shè)置參考2)。最后,業(yè)務(wù)執(zhí)行時(shí)間長(zhǎng)的問(wèn)題,也可能需要分析一下,看看能不能使用中間件對(duì)任務(wù)進(jìn)行拆分和解耦。

多線程的實(shí)現(xiàn)和啟動(dòng)

callable與runable區(qū)別

syncrhoized,reentrantLock各自特點(diǎn)和比對(duì)

線程池

future異步方式獲取執(zhí)行結(jié)果

concurrent包

lock

線程協(xié)作:

  • CountDownLatch:這個(gè)類(lèi)是為了幫助猿友們方便的實(shí)現(xiàn)一個(gè)這樣的場(chǎng)景,就是某一個(gè)線程需要等待其它若干個(gè)線程完成某件事以后才能繼續(xù)進(jìn)行
  • CyclicBarrier:這個(gè)類(lèi)是為了幫助猿友們方便的實(shí)現(xiàn)多個(gè)線程一起啟動(dòng)的場(chǎng)景,就像賽跑一樣,只要大家都準(zhǔn)備好了,那就開(kāi)始一起沖。比如下面這個(gè)程序,所有的線程都準(zhǔn)備好了,才會(huì)一起開(kāi)始執(zhí)行。
  • Semaphore:這個(gè)類(lèi)是為了幫助猿友們方便的實(shí)現(xiàn)控制數(shù)量的場(chǎng)景,可以是線程數(shù)量或者任務(wù)數(shù)量等等。來(lái)看看下面這段簡(jiǎn)單的代碼。
  • Exchanger:這個(gè)類(lèi)是為了幫助猿友們方便的實(shí)現(xiàn)兩個(gè)線程交換數(shù)據(jù)的場(chǎng)景,使用起來(lái)非常簡(jiǎn)單,看看下面這段代碼。

以上就是動(dòng)力節(jié)點(diǎn)小編介紹的"Java多線程并發(fā)編程",希望對(duì)大家有幫助,如有疑問(wèn),請(qǐng)?jiān)诰€咨詢(xún),有專(zhuān)業(yè)老師隨時(shí)為您服務(wù)。

提交申請(qǐng)后,顧問(wèn)老師會(huì)電話(huà)與您溝通安排學(xué)習(xí)

  • 全國(guó)校區(qū) 2025-05-15 搶座中
  • 全國(guó)校區(qū) 2025-06-05 搶座中
  • 全國(guó)校區(qū) 2025-06-26 搶座中
免費(fèi)課程推薦 >>
技術(shù)文檔推薦 >>
主站蜘蛛池模板: 中文字幕亚洲图片 | 亚洲综合日韩在线亚洲欧美专区 | 成人毛片免费观看视频在线 | 涩涩色视频在线播放 | 国产伦久视频免费观看 视频 | 亚洲永久中文字幕在线 | 亚洲国产日韩a在线亚洲 | dy888午夜国产精品不卡 | 在线成人爽a毛片免费软件 在线成人影片 | 在线日韩中文字幕 | 天天操天天曰 | 久久免费成人 | 国产片久久 | 亚洲视频a | 色狠狠xx| 日日噜噜夜夜狠狠久久aⅴ 日日噜噜夜夜狠狠久久丁香七 | 一二三四社区在线视频社区 | 欧美日韩 国产区 在线观看 | 成年人网站在线免费观看 | 欧美日韩中文字幕 | 国产粉嫩嫩00在线正在播放 | 美女羞羞免费网站 | 色噜噜狠狠色综合免费视频 | 欧美精品一区二区三区视频 | 黄色网址免费大全 | 久久中文字幕免费 | 玖玖玖精品视频免费播放 | 午夜看一级特黄a大片黑 | 亚洲成a人片77777老司机 | 亚洲乱码一二三四区国产 | 黄a在线| 欧美大成色www永久网站婷 | a天堂v| 欧美激情综合亚洲一二区 | 麻豆精品国产剧情在线观看 | 一级毛片无毒不卡直接观看 | 看片网站在线 | 涩涩涩丁香色婷五月网视色 | 99精品视频99 | 麻豆一区二区大豆行情 | 一级毛片在线免费播放 |