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

溫馨提示×

溫馨提示×

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

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

java怎么使用多線程解決主線程提前結束問題

發布時間:2023-03-10 09:51:13 來源:億速云 閱讀:153 作者:iii 欄目:開發技術

這篇文章主要介紹“java怎么使用多線程解決主線程提前結束問題”,在日常操作中,相信很多人在java怎么使用多線程解決主線程提前結束問題問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”java怎么使用多線程解決主線程提前結束問題”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

CountDownLatch

  • CountDownLatch(也叫閉鎖)是一個同步協助類,允許一個或多個線程等待,直到其他線程完成操作集。

  • CountDownLatch 使用給定的計數值(count)初始化。await 方法會阻塞直到當前的計數值(count)由于 countDown 方法的調用達到 0,count 為 0 之后所有等待的線程都會被釋放,并且隨后對await方法的調用都會立即返回。

構造方法:

//參數count為計數值
public CountDownLatch(int count) {};

常用方法

// 調用 await() 方法的線程會被掛起,它會等待直到 count 值為 0 才繼續執行
public void await() throws InterruptedException {};
 
// 和 await() 類似,若等待 timeout 時長后,count 值還是沒有變為 0,不再等待,繼續執行
public boolean await(long timeout, TimeUnit unit) throws InterruptedException {};
 
// 會將 count 減 1,直至為 0
public void countDown() {};

使用案例

  • 首先是創建實例 CountDownLatch countDown = new CountDownLatch(2);

  • 需要同步的線程執行完之后,計數 -1, countDown.countDown();

  • 需要等待其他線程執行完畢之后,再運行的線程,調用 countDown.await()實現阻塞同步。

  • 如下。

應用場景

CountDownLatch 一般用作多線程倒計時計數器,強制它們等待其他一組(CountDownLatch的初始化決定)任務執行完成。

CountDownLatch的兩種使用場景:

  • 讓多個線程等待,模擬并發。

  • 讓單個線程等待,多個線程(任務)完成后,進行匯總合并。

場景1:模擬并發

import java.util.concurrent.CountDownLatch;
 
/**
 * 讓多個線程等待:模擬并發,讓并發線程一起執行
 */
public class CountDownLatchTest {
    public static void main(String[] args) throws InterruptedException {
 
        CountDownLatch countDownLatch = new CountDownLatch(1);
        
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                try {
                    // 等待
                    countDownLatch.await();
                    String parter = "【" + Thread.currentThread().getName() + "】";
                    System.out.println(parter + "開始執行……");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
 
        Thread.sleep(2000);
       
        countDownLatch.countDown();
    }
}

場景2:多個線程完成后,進行匯總合并

很多時候,我們的并發任務,存在前后依賴關系;比如數據詳情頁需要同時調用多個接口獲取數據,并發請求獲取到數據后、需要進行結果合并;或者多個數據操作完成后,需要數據 check;這其實都是:在多個線程(任務)完成后,進行匯總合并的場景。

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
 
/**
 * 讓單個線程等待:多個線程(任務)完成后,進行匯總合并
 */
public class CountDownLatchTest3 {
 
    //用于聚合所有的統計指標
    private static Map map = new ConcurrentHashMap();
    //創建計數器,這里需要統計4個指標
    private static CountDownLatch countDownLatch = new CountDownLatch(4);
 
    public static void main(String[] args) throws Exception {
 
        //記錄開始時間
        long startTime = System.currentTimeMillis();
 
        Thread countUserThread = new Thread(() -> {
            try {
                System.out.println("正在統計新增用戶數量");
                Thread.sleep(3000);//任務執行需要3秒
                map.put("userNumber", 100);//保存結果值
                System.out.println("統計新增用戶數量完畢");
                countDownLatch.countDown();//標記已經完成一個任務
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        Thread countOrderThread = new Thread(() -> {
            try {
                System.out.println("正在統計訂單數量");
                Thread.sleep(3000);//任務執行需要3秒
                map.put("countOrder", 20);//保存結果值
                System.out.println("統計訂單數量完畢");
                countDownLatch.countDown();//標記已經完成一個任務
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
 
        Thread countGoodsThread = new Thread(() -> {
            try {
                System.out.println("正在商品銷量");
                Thread.sleep(3000);//任務執行需要3秒
                map.put("countGoods", 300);//保存結果值
                System.out.println("統計商品銷量完畢");
                countDownLatch.countDown();//標記已經完成一個任務
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
 
        Thread countmoneyThread = new Thread(() -> {
            try {
                System.out.println("正在總銷售額");
                Thread.sleep(3000);//任務執行需要3秒
                map.put("countMoney", 40000);//保存結果值
                System.out.println("統計銷售額完畢");
                countDownLatch.countDown();//標記已經完成一個任務
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        
        //啟動子線程執行任務
        countUserThread.start();
        countGoodsThread.start();
        countOrderThread.start();
        countmoneyThread.start();
 
        try {
            //主線程等待所有統計指標執行完畢
            countDownLatch.await();
            long endTime = System.currentTimeMillis();//記錄結束時間
            System.out.println("------統計指標全部完成--------");
            System.out.println("統計結果為:" + map);
            System.out.println("任務總執行時間為" + (endTime - startTime) + "ms");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
 
    }
}

接下來進入正題

使用多線程代替for循環提高查詢效率,并且防止主線程提前結束導致其他線程數據錯誤

直接上代碼:

@Override
    public AppResponse getLocations() throws InterruptedException {
        List<GetLocationVO> vos = new ArrayList<>();
        vos = projectDao.getLocationOne();    
//      原來的代碼
//        for (GetLocationVO vo : vos) {
//            List<LocationVO> children = projectDao.getLocationChildren(vo.getId());
//            vo.setChildren(children);
//        }
        //改造后的代碼
        Thread(vos,10);
        return AppResponse.success("查詢成功",vos);
    }
 
    //此處有加鎖
    public synchronized void Thread(List<GetLocationVO> list, int nThread) throws InterruptedException {
        if (CollectionUtils.isEmpty(list) || nThread <= 0 || CollectionUtils.isEmpty(list)) {
            return;
        }
        CountDownLatch latch = new CountDownLatch(list.size());//創建一個計數器(大小為當前數組的大小,確保所有執行完主線程才結束)
        ExecutorService pool = Executors.newFixedThreadPool(nThread);//創建一個固定的線程池
        for (GetLocationVO vo : list) {
            pool.execute(() -> {
                //處理的業務
                List<LocationVO> children = projectDao.getLocationChildren(vo.getId());
                vo.setChildren(children);
                latch.countDown();
            });
        }
        latch.await();
        pool.shutdown();
    }

到此,關于“java怎么使用多線程解決主線程提前結束問題”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

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

AI

江都市| 明星| 兴义市| 皮山县| 碌曲县| 怀集县| 盘锦市| 正安县| 勃利县| 陇南市| 赣榆县| 嘉黎县| 怀来县| 西平县| 富顺县| 岚皋县| 台中市| 太谷县| 白山市| 辽阳县| 武邑县| 娱乐| 岫岩| 从化市| 镇平县| 铁力市| 大荔县| 华容县| 福清市| 河西区| 永川市| 巴林左旗| 怀柔区| 巴南区| 绥芬河市| 博野县| 扶绥县| 班玛县| 武平县| 锦屏县| 大荔县|