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

Java 用兩個線程交替打印數(shù)字和字母

 更新時間:2021年03月31日 09:37:27   作者:Bridge Li  
這篇文章主要介紹了Java 用兩個線程交替打印數(shù)字和字母的方法,幫助大家更好的理解和學習使用Java,感興趣的朋友可以了解下

前一段時間聽馬士兵老師講課,講到某公司的一個面試,兩個線程,其中一個線程輸出ABC,另一個線程輸出123,如何控制兩個線程交叉輸出1A2B3C,由于本人多線程掌握的一直不是很好,所以聽完這道題,個人感覺收獲良多,這是一個學習筆記。這道題有多種解法,不過有些屬于純炫技,所以只記錄常見的三種解法。首先看第一種

1. park 和 unpark

package cn.bridgeli.demo;
 
import com.google.common.collect.Lists;
 
import java.util.List;
import java.util.concurrent.locks.LockSupport;
 
/**
 * @author BridgeLi
 * @date 2021/2/6 16:14
 */
public class Thread_Communication_Park_Unpark {
 
    static Thread t1 = null;
    static Thread t2 = null;
 
    public static void main(String[] args) {
 
        final List<Integer> integers = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7);
        final List<String> strings = Lists.newArrayList("A", "B", "C", "D", "E", "F", "G");
 
        t1 = new Thread(() -> integers.forEach(item -> {
            System.out.print(item);
            LockSupport.unpark(t2);
            LockSupport.park();
        }), "t1");
 
        t2 = new Thread(() -> strings.forEach(item -> {
            LockSupport.park();
            System.out.print(item);
            LockSupport.unpark(t1);
        }), "t2");
 
        t1.start();
        t2.start();
    }
 
}

這個是最簡單的實現(xiàn)方法,LockSupport.park() 使當前線程阻塞,而 LockSupport.unpark() 則表示喚醒一個線程,所以他需要一個參數(shù),表示你要喚醒哪個線程,很好理解,也比較簡單。

2. synchronized、notify、wait

package cn.bridgeli.demo;
 
import com.google.common.collect.Lists;
 
import java.util.List;
 
/**
 * @author BridgeLi
 * @date 2021/2/6 16:14
 */
public class Thread_Communication_Notify_Wait {
 
    public static void main(String[] args) {
 
        final Object o = new Object();
        final List<Integer> integers = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7);
        final List<String> strings = Lists.newArrayList("A", "B", "C", "D", "E", "F", "G");
 
        new Thread(() -> {
            synchronized (o) {
                integers.forEach(item -> {
                    System.out.print(item);
                    o.notify();
                    try {
                        o.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                });
 
                o.notify();
            }
        }, "t1").start();
 
        new Thread(() -> {
            synchronized (o) {
                strings.forEach(item -> {
                    System.out.print(item);
                    o.notify();
                    try {
                        o.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                });
                o.notify();
            }
        }, "t2").start();
    }
}

這是一個比較傳統(tǒng)的寫法,也是比較難理解的一個寫法,掌握了這種寫法之后,對 synchronized、notify、wait 的認識也會有一個新高度,下面就簡單解析一下這種寫法:

我們都知道 synchronized 是一把鎖,而鎖是什么?就是一個第三方的互斥的一個資源,所以 synchronized (o),就表示我們對 o 這個對象加鎖,是通過修改 o 的對象頭實現(xiàn)的,也就是兩個線程誰成功修改了 o 的對象頭,那么誰就拿到了這把鎖,然后就可以執(zhí)行里面的相關(guān)邏輯,而沒有成功修改 o 的對象頭的線程,就只有進入到對象 o 的一個等待隊列,等待被系統(tǒng)調(diào)度執(zhí)行(這是一個比較簡單的不是很準確說法,詳細過程,等我將來再寫一個文章想聊鎖升級的過程);然后就是 o.notify(),剛說過 synchronized (o) 一堆線程爭搶鎖,沒有搶到鎖的線程進入對象 o 的等待隊列,所以 o.notify() 含義就是從對象 o 的等待隊列中隨機叫醒一個線程,然后執(zhí)行;最后是 o.wait() 的含義,他的含義也很簡單,就是當前線程放到對象 o 的等待隊列中,讓出 CPU。

通過這段描述,所以大家肯定也可以學習到經(jīng)常遇到的三個問題是怎么回事:1. wait 是否占用 CPU 資源,因為進入了等待隊列,所以是不會占用的;2. 既然 notify、wait 是讓喚醒線程和讓線程進入等待的,為什么不是 Thread 類的方法,反而是 Object 的方法,因為 notify、wait 是配合 synchronized 一起使用的,不一定用在多線程中,他們控制的是 synchronized 鎖定的對象的等待隊列,而 synchronized 鎖定的對象,肯定是一個 Object,所以 notify、wait 比如是 Object 對象的方法;3. 關(guān)于 synchronized (o) 括號里面是一個對象實例、Class 對象、鎖定代碼塊、靜態(tài)變量等等區(qū)別,只要明白 synchronized 修改的是什么,這些區(qū)別就一目了然了,不再贅述。

最后要說明的一個問題是:循環(huán)外邊的 o.notify() 必不可少,有些同學寫的時候可能隨手就忘記了,或者不知道為什么需要最后再 notify 一下,其實仔細想一想就可以明白了,假設(shè)最后執(zhí)行的是輸出字母的線程,那么他之前一定是被執(zhí)行輸出數(shù)字的線程喚醒的,而執(zhí)行輸出數(shù)字的這個線程喚醒執(zhí)行輸出字母的線程之后,自身就進入等待隊列了,所以循環(huán)結(jié)束之后,如果最后執(zhí)行輸出字母的線程沒有喚醒執(zhí)行輸出數(shù)字的線程的話,那么執(zhí)行輸出數(shù)字的線程會一直 wait 阻塞在那里,將等到天荒地來海枯石爛永遠無法結(jié)束。

3. Condition

package cn.bridgeli.demo;
 
import com.google.common.collect.Lists;
 
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
 
/**
 * @author BridgeLi
 * @date 2021/2/6 16:14
 */
public class Thread_Communication_Condition {
 
    public static void main(String[] args) {
 
        final List<Integer> integers = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7);
        final List<String> strings = Lists.newArrayList("A", "B", "C", "D", "E", "F", "G");
 
        Lock lock = new ReentrantLock();
        Condition condition1 = lock.newCondition();
        Condition condition2 = lock.newCondition();
 
        new Thread(() -> {
            lock.lock();
            try {
                integers.forEach(item -> {
                    System.out.print(item);
                    condition2.signal();
                    try {
                        condition1.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                });
 
                condition2.signal();
            } finally {
                lock.unlock();
            }
        }, "t1").start();
 
        new Thread(() -> {
            lock.lock();
            try {
                strings.forEach(item -> {
                    System.out.print(item);
                    condition1.signal();
                    try {
                        condition2.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                });
                condition1.signal();
            } finally {
                lock.unlock();
            }
        }, "t2").start();
 
    }
 
}

當我們理解了上面兩種寫法之后,那么最后這個寫法其實也比較容易理解了,就不用我多贅言了。

如果有幸有同學看到了這里,那么我再提出一個小問題,可以思考一下怎么解決,后面兩種寫法,我們保證是執(zhí)行輸出數(shù)字的線程還是執(zhí)行輸出字母的線程先執(zhí)行,也就是先輸出數(shù)字或者字母嗎?如果不能的話,現(xiàn)在業(yè)務(wù)需求要求必須是先輸出字母或者數(shù)字怎么做?(提示:CAS 自旋)

以上就是Java 用兩個線程交替打印數(shù)字和字母的詳細內(nèi)容,更多關(guān)于Java 線程交替打印的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 如何基于JAVA讀取yml配置文件指定key內(nèi)容

    如何基于JAVA讀取yml配置文件指定key內(nèi)容

    這篇文章主要介紹了如何基于JAVA讀取yml配置文件指定key內(nèi)容,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-01-01
  • Mybatis?Web中的數(shù)據(jù)庫操作方法舉例詳解

    Mybatis?Web中的數(shù)據(jù)庫操作方法舉例詳解

    Mybatis是一款優(yōu)秀的持久化框架,用于簡化JDBC的開發(fā),下面這篇文章主要給大家介紹了關(guān)于Mybatis?Web中數(shù)據(jù)庫操作方法的相關(guān)資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-09-09
  • Java 代碼檢查工具之PMD入門使用詳細教程

    Java 代碼檢查工具之PMD入門使用詳細教程

    這篇文章主要介紹了Java 代碼檢查工具之PMD入門使用詳細教程,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-03-03
  • springboot中用fastjson處理返回值為null的屬性值

    springboot中用fastjson處理返回值為null的屬性值

    在本篇文章里小編給大家整理的是一篇關(guān)于springboot中用fastjson處理返回值問題詳解內(nèi)容,需要的朋友們參考下。
    2020-03-03
  • Nacos源碼閱讀方法

    Nacos源碼閱讀方法

    這篇文章將會帶大家閱讀Nacos源碼以及教大家閱讀源碼的技巧,感興趣的朋友跟隨小編一起看看Nacos源碼閱讀方法
    2022-03-03
  • 最簡單易懂的java數(shù)組排序方法整理

    最簡單易懂的java數(shù)組排序方法整理

    這篇文章主要給大家整理介紹了最簡單易懂的java數(shù)組排序方法,文中通過示例代碼介紹的非常詳細,對大家學習或者使用java具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-07-07
  • Spring?Boot?條件注解詳情

    Spring?Boot?條件注解詳情

    這篇文章主要介紹了Spring?Boot?條件注解詳情,SpringBoot條件注解@Conditional,可用于根據(jù)某個特定的條件來判斷是否需要創(chuàng)建某個特定的Bean,下文更多相關(guān)介紹,需要的小伙伴可以參考一下
    2022-05-05
  • Spring?Validation參數(shù)效驗的各種使用姿勢總結(jié)

    Spring?Validation參數(shù)效驗的各種使用姿勢總結(jié)

    在實際項目中經(jīng)常需要對前段傳來的數(shù)據(jù)進行校驗,下面這篇文章主要給大家介紹了關(guān)于Spring?Validation參數(shù)效驗的各種使用姿勢,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-04-04
  • springboot整合nacos的入門Demo及Nacos安裝部署

    springboot整合nacos的入門Demo及Nacos安裝部署

    Nacos?提供了一組簡單易用的特性集,幫助您快速實現(xiàn)動態(tài)服務(wù)發(fā)現(xiàn)、服務(wù)配置、服務(wù)元數(shù)據(jù)及流量管理,Nacos?致力于幫助您發(fā)現(xiàn)、配置和管理微服務(wù),這篇文章主要介紹了springboot整合nacos的入門Demo,需要的朋友可以參考下
    2024-01-01
  • Java替換中使用正則表達式實現(xiàn)中間模糊匹配的方法

    Java替換中使用正則表達式實現(xiàn)中間模糊匹配的方法

    今天小編就為大家分享一篇Java替換中使用正則表達式實現(xiàn)中間模糊匹配的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-07-07

最新評論

西城区| 大理市| 汝南县| 且末县| 金阳县| 陇南市| 蓬莱市| 湘乡市| 明溪县| 安吉县| 房山区| 沙坪坝区| 漳平市| 镇江市| 竹北市| 敖汉旗| 琼结县| 团风县| 双峰县| 灵寿县| 宁晋县| 沙洋县| 尉氏县| 蚌埠市| 富民县| 文安县| 海阳市| 芒康县| 安平县| 莱西市| 贵南县| 临桂县| 成安县| 太原市| 汤阴县| 化州市| 个旧市| 宝鸡市| 河间市| 阳原县| 文水县|