大战熟女丰满人妻av-荡女精品导航-岛国aaaa级午夜福利片-岛国av动作片在线观看-岛国av无码免费无禁网站-岛国大片激情做爰视频

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

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

更新時間:2021-05-17 15:54:59 來源:動力節(jié)點 瀏覽1998次

1. 為什么要用多線程

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

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

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

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

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

(1)繼承Thread類

用戶的線程類只須繼承Thread類并重寫其run()方法即可,通過調(diào)用用戶線程類的start()方法即可啟動用戶線程

class MyThread extends Thread{
  public void run(){

  }
}

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

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

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

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

    }
}

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

3. 線程的生命周期

4. 線程安全

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

線程安全也是有幾個級別的:

(1)不可變

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

(2)絕對線程安全

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

(3)相對線程安全

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

(4)線程非安全

這個就沒什么好說的了,ArrayList、LinkedList、HashMap等都是線程非安全的類

5. 鎖

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

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

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

6. 線程間操作

(1)線程間的通信

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

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

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

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

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

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

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

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

方式二:若每個線程執(zhí)行任務(wù)不同,可以將兩個任務(wù)方法放到一個類中,然后將data也放在這個類中,然后傳到不同的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 ++) { //開啟兩個線程增加data
            new Thread(new Runnable() {
                @Override
                public void run() {
                    task.increment();
                }
            }).start();
        }
        for(int i = 0; i < 2; i ++) { //開啟兩個線程減少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)建和銷毀線程,達(dá)到線程對象的重用。另外,使用線程池還可以根據(jù)項目靈活地控制并發(fā)的數(shù)目。

(1)ThreadPoolExecutor類

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

public class ThreadPoolExecutor extends AbstractExecutorService {
/**
*corePoolSize:核心池的大小
*maximumPoolSize:線程池最大線程數(shù)
*keepAliveTime:表示線程沒有任務(wù)執(zhí)行時最多保持多久時間會終止
*unit:參數(shù)keepAliveTime的時間單位,有7種取值,在TimeUnit類中有7種靜態(tài)屬性
*    TimeUnit.DAYS;               //天
*    TimeUnit.HOURS;             //小時
*    TimeUnit.MINUTES;           //分鐘
*    TimeUnit.SECONDS;           //秒
*    TimeUnit.MILLISECONDS;      //毫秒
*    TimeUnit.MICROSECONDS;      //微妙
*    TimeUnit.NANOSECONDS;       //納秒
*workQueue:一個阻塞隊列,用來存儲等待執(zhí)行的任務(wù)
*    ArrayBlockingQueue;
*    LinkedBlockingQueue;
*    SynchronousQueue;
*threadFactory:線程工廠,主要用來創(chuàng)建線程
*handler:表示當(dāng)拒絕處理任務(wù)時的策略,有以下四種取值
*    ThreadPoolExecutor.AbortPolicy:丟棄任務(wù)并拋出RejectedExecutionException異常。
*    ThreadPoolExecutor.DiscardPolicy:也是丟棄任務(wù),但是不拋出異常。
*    ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務(wù),然后重新嘗試執(zhí)行任務(wù)(重復(fù)此過程)
*    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()方法實際上是Executor中聲明的方法,在ThreadPoolExecutor進(jìn)行了具體的實現(xiàn),這個方法是ThreadPoolExecutor的核心方法,通過這個方法可以向線程池提交一個任務(wù),交由線程池去執(zhí)行。

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

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

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

(2)使用示例

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

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

使用示例:

public class ThreadPoolTest{
    public static void main(String[] args){
        // 創(chuàng)建一個容量為5的線程池
        ExecutorService executorService = Executors.newFixedThreadPool(5);
    // 向線程池提交一個任務(wù)(其實就是通過線程池來啟動一個線程)
    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)其他問題

1)如果你提交任務(wù)時,線程池隊列已滿,這時會發(fā)生什么

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

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

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

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

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

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

多線程的實現(xiàn)和啟動

callable與runable區(qū)別

syncrhoized,reentrantLock各自特點和比對

線程池

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

concurrent包

lock

線程協(xié)作:

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

以上就是動力節(jié)點小編介紹的"Java多線程并發(fā)編程",希望對大家有幫助,如有疑問,請在線咨詢,有專業(yè)老師隨時為您服務(wù)。

提交申請后,顧問老師會電話與您溝通安排學(xué)習(xí)

免費課程推薦 >>
技術(shù)文檔推薦 >>
主站蜘蛛池模板: 天天天天天天操 | 一级毛片a女人刺激视频免费 | 日本高清专区一区二无线 | 日韩在线成人 | 综合久久91 | 一级片播放 | 99热这里只有精品7 99热这里只有精品8 | 手机在线一区二区三区 | 日韩中文字幕免费 | 四虎影永久在线高清免费 | 亚洲视频在线播放 | 99热久久国产精品这 | 久久国产国内精品对话对白 | 免费一级毛片无毒不卡 | 婷婷色基地 | 奇米第四色7777 | 中文字幕日韩在线一区国内 | 亚洲精品乱码久久久久久v 亚洲精品乱码久久久久久麻豆 | 久草香蕉视频在线观看 | 亚洲免费视频一区二区三区 | 国产精品亚洲精品一区二区三区 | 亚州色拍拍拍 | 国产精品一区二区久久沈樵 | 日操夜操 | 久久精品只有这里有 | 欧美一区二区三区高清视频 | 男女性高清爱潮视频免费观看 | 91手机在线视频观看 | 亚洲综合国产精品 | 欧美巨大xxxx做受孕妇视频 | 久久精品啪啪嗷嗷叫 | 精品免费久久久久久成人影院 | 日本亚洲欧洲高清有码在线播放 | 久久国产乱子伦精品免 | 日日夜夜网站 | 大ji吧快给我别停受不了视频 | 日本高清一级片 | 欧美一级毛片高清免费观看 | 亚洲高清国产一区二区三区 | 中文字幕亚洲综合久久202 | 99看片网|