成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Java多線程學(xué)習(xí)(五)線程間通信知識(shí)點(diǎn)補(bǔ)充

mating / 675人閱讀

摘要:我們通過之前幾章的學(xué)習(xí)已經(jīng)知道在線程間通信用到的關(guān)鍵字關(guān)鍵字以及等待通知機(jī)制。今天我們就來講一下線程間通信的其他知識(shí)點(diǎn)管道輸入輸出流的使用的使用。將當(dāng)前線程的此線程局部變量的副本設(shè)置為指定的值刪除此線程局部變量的當(dāng)前線程的值。

系列文章傳送門:

Java多線程學(xué)習(xí)(一)Java多線程入門

Java多線程學(xué)習(xí)(二)synchronized關(guān)鍵字(1)

java多線程學(xué)習(xí)(二)synchronized關(guān)鍵字(2)

Java多線程學(xué)習(xí)(三)volatile關(guān)鍵字

Java多線程學(xué)習(xí)(四)等待/通知(wait/notify)機(jī)制

Java多線程學(xué)習(xí)(五)線程間通信知識(shí)點(diǎn)補(bǔ)充

Java多線程學(xué)習(xí)(六)Lock鎖的使用

Java多線程學(xué)習(xí)(七)并發(fā)編程中一些問題

系列文章將被優(yōu)先更新于微信公眾號(hào)“Java面試通關(guān)手冊”,歡迎廣大Java程序員和愛好技術(shù)的人員關(guān)注。

本節(jié)思維導(dǎo)圖:

思維導(dǎo)圖源文件+思維導(dǎo)圖軟件關(guān)注微信公眾號(hào):“Java面試通關(guān)手冊” 回復(fù)關(guān)鍵字:“Java多線程” 免費(fèi)領(lǐng)取。

我們通過之前幾章的學(xué)習(xí)已經(jīng)知道在線程間通信用到的synchronized關(guān)鍵字、volatile關(guān)鍵字以及等待/通知(wait/notify)機(jī)制。今天我們就來講一下線程間通信的其他知識(shí)點(diǎn):管道輸入/輸出流、Thread.join()的使用、ThreadLocal的使用。

一 管道輸入/輸出流

管道輸入/輸出流和普通文件的輸入/輸出流或者網(wǎng)絡(luò)輸入、輸出流不同之處在于管道輸入/輸出流主要用于線程之間的數(shù)據(jù)傳輸,而且傳輸?shù)拿浇闉?strong>內(nèi)存。

管道輸入/輸出流主要包括下列兩類的實(shí)現(xiàn):

面向字節(jié): PipedOutputStream、 PipedInputStream

面向字符: PipedWriter、 PipedReader

1.1 第一個(gè)管道輸入/輸出流實(shí)例

完整代碼:https://github.com/Snailclimb/threadDemo/tree/master/src/pipedInputOutput

writeMethod方法

    public void writeMethod(PipedOutputStream out) {
        try {
            System.out.println("write :");
            for (int i = 0; i < 300; i++) {
                String outData = "" + (i + 1);
                out.write(outData.getBytes());
                System.out.print(outData);
            }
            System.out.println();
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

readMethod方法

    public void readMethod(PipedInputStream input) {
        try {
            System.out.println("read  :");
            byte[] byteArray = new byte[20];
            int readLength = input.read(byteArray);
            while (readLength != -1) {
                String newData = new String(byteArray, 0, readLength);
                System.out.print(newData);
                readLength = input.read(byteArray);
            }
            System.out.println();
            input.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

測試方法

    public static void main(String[] args) {

        try {
            WriteData writeData = new WriteData();
            ReadData readData = new ReadData();

            PipedInputStream inputStream = new PipedInputStream();
            PipedOutputStream outputStream = new PipedOutputStream();

            // inputStream.connect(outputStream);
            outputStream.connect(inputStream);

            ThreadRead threadRead = new ThreadRead(readData, inputStream);
            threadRead.start();

            Thread.sleep(2000);

            ThreadWrite threadWrite = new ThreadWrite(writeData, outputStream);
            threadWrite.start();

        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

我們上面定義了兩個(gè)方法writeMethodreadMethod,前者用于寫字節(jié)/字符(取決于你用的是PipedOuputStream還是PipedWriter),后者用于讀取字節(jié)/字符(取決于你用的是PipedInputStream還是PipedReader).我們定義了兩個(gè)線程threadReadthreadWrite ,threadRead線程運(yùn)行readMethod方法,threadWrite運(yùn)行writeMethod方法。然后 通過outputStream.connect(inputStream)inputStream.connect(outputStream)使兩個(gè)管道流產(chǎn)生鏈接,這樣就可以將數(shù)據(jù)進(jìn)行輸入與輸出了。

運(yùn)行結(jié)果:

二 Thread.join()的使用

在很多情況下,主線程生成并起動(dòng)了子線程,如果子線程里要進(jìn)行大量的耗時(shí)的運(yùn)算,主線程往往將于子線程之前結(jié)束,但是如果主線程處理完其他的事務(wù)后,需要用到子線程的處理結(jié)果,也就是主線程需要等待子線程執(zhí)行完成之后再結(jié)束,這個(gè)時(shí)候就要用到j(luò)oin()方法了。另外,一個(gè)線程需要等待另一個(gè)線程也需要用到j(luò)oin()方法。

Thread類除了提供join()方法之外,還提供了join(long millis)、join(long millis, int nanos)兩個(gè)具有超時(shí)特性的方法。這兩個(gè)超時(shí)方法表示,如果線程thread在指定的超時(shí)時(shí)間沒有終止,那么將會(huì)從該超時(shí)方法中返回。

2.1 join方法使用

不使用join方法的弊端演示:

Test.java

public class Test {

    public static void main(String[] args) throws InterruptedException {

        MyThread threadTest = new MyThread();
        threadTest.start();

        //Thread.sleep(?);//因?yàn)椴恢雷泳€程要花的時(shí)間這里不知道填多少時(shí)間
        System.out.println("我想當(dāng)threadTest對(duì)象執(zhí)行完畢后我再執(zhí)行");
    }
    static public class MyThread extends Thread {

        @Override
        public void run() {
            System.out.println("我想先執(zhí)行");
        }

    }
}

運(yùn)行結(jié)果:

可以看到子線程中后被執(zhí)行,這里的例子只是一個(gè)簡單的演示,我們想一下:假如子線程運(yùn)行的結(jié)果被主線程運(yùn)行需要怎么辦? sleep方法? 當(dāng)然可以,但是子線程運(yùn)行需要的時(shí)間是不確定的,所以sleep多長時(shí)間當(dāng)然也就不確定了。這里就需要使用join方法解決上面的問題。

使用join方法解決上面的問題:

Test.java

public class Test {

    public static void main(String[] args) throws InterruptedException {

        MyThread threadTest = new MyThread();
        threadTest.start();

        //Thread.sleep(?);//因?yàn)椴恢雷泳€程要花的時(shí)間這里不知道填多少時(shí)間
        threadTest.join();
        System.out.println("我想當(dāng)threadTest對(duì)象執(zhí)行完畢后我再執(zhí)行");
    }
    static public class MyThread extends Thread {

        @Override
        public void run() {
            System.out.println("我想先執(zhí)行");
        }

    }
}

上面的代碼僅僅加上了一句:threadTest.join();。在這里join方法的作用就是主線程需要等待子線程執(zhí)行完成之后再結(jié)束。

2.2 join(long millis)方法的使用

join(long millis)中的參數(shù)就是設(shè)定的等待時(shí)間。

JoinLongTest.java

public class JoinLongTest {

    public static void main(String[] args) {
        try {
            MyThread threadTest = new MyThread();
            threadTest.start();

            threadTest.join(2000);// 只等2秒
            //Thread.sleep(2000);

            System.out.println("  end timer=" + System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    static public class MyThread extends Thread {

        @Override
        public void run() {
            try {
                System.out.println("begin Timer=" + System.currentTimeMillis());
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}

運(yùn)行結(jié)果:

不管是運(yùn)行threadTest.join(2000)還是Thread.sleep(2000), “end timer=1522036620288”語句的輸出都是間隔兩秒,“end timer=1522036620288”語句輸出后該程序還會(huì)運(yùn)行一段時(shí)間,因?yàn)榫€程中的run方法中有Thread.sleep(10000)語句

另外threadTest.join(2000)Thread.sleep(2000) 和區(qū)別在于: Thread.sleep(2000)不會(huì)釋放鎖,threadTest.join(2000)會(huì)釋放鎖

三 ThreadLocal的使用

變量值的共享可以使用public static變量的形式,所有線程都使用一個(gè)public static變量。如果想實(shí)現(xiàn)每一個(gè)線程都有自己的共享變量該如何解決呢?JDK中提供的ThreadLocal類正是為了解決這樣的問題。ThreadLocal類主要解決的就是讓每個(gè)線程綁定自己的值,可以將ThreadLocal類形象的比喻成存放數(shù)據(jù)的盒子,盒子中可以存儲(chǔ)每個(gè)線程的私有數(shù)據(jù)。

再舉個(gè)簡單的例子:
比如有兩個(gè)人去寶屋收集寶物,這兩個(gè)共用一個(gè)袋子的話肯定會(huì)產(chǎn)生爭執(zhí),但是給他們兩個(gè)人每個(gè)人分配一個(gè)袋子的話就不會(huì)出現(xiàn)這樣的問題。如果把這兩個(gè)人比作線程的話,那么ThreadLocal就是用來這兩個(gè)線程競爭的。

ThreadLocal類相關(guān)方法:
| 方法名稱 | 描述 |
| :-------- | --------:|
| get() | 返回當(dāng)前線程的此線程局部變量的副本中的值。 |
| set(T value) | 將當(dāng)前線程的此線程局部變量的副本設(shè)置為指定的值 |
| remove() | 刪除此線程局部變量的當(dāng)前線程的值。|
| initialValue() | 返回此線程局部變量的當(dāng)前線程的“初始值” |

3.1 ThreadLocal類的初試

Test1.java

public class Test1 {
    public static ThreadLocal t1 = new ThreadLocal();

    public static void main(String[] args) {
        if (t1.get() == null) {
            System.out.println("為ThreadLocal類對(duì)象放入值:aaa");
            t1.set("aaa?");
        }
        System.out.println(t1.get());
        System.out.println(t1.get());
    }

}

從運(yùn)行結(jié)果可以看出,第一次調(diào)用ThreadLocal對(duì)象的get()方法時(shí)返回的值是null,通過調(diào)用set()方法可以為ThreadLocal對(duì)象賦值。

如果想要解決get()方法null的問題,可以使用ThreadLocal對(duì)象的initialValue方法。如下:

Test2.java

public class Test2 {
    public static ThreadLocalExt t1 = new ThreadLocalExt();

    public static void main(String[] args) {
        if (t1.get() == null) {
            System.out.println("從未放過值");
            t1.set("我的值");
        }
        System.out.println(t1.get());
        System.out.println(t1.get());
    }
    static public class ThreadLocalExt extends ThreadLocal {
        @Override
        protected Object initialValue() {
            return "我是默認(rèn)值 第一次get不再為null";
        }
    }


}
3.2 驗(yàn)證線程變量間的隔離性

Test3.java

/**
 *TODO 驗(yàn)證線程變量間的隔離性
 */
public class Test3 {

    public static void main(String[] args) {
        try {
            for (int i = 0; i < 10; i++) {
                System.out.println("       在Main線程中取值=" + Tools.tl.get());
                Thread.sleep(100);
            }
            Thread.sleep(5000);
            ThreadA a = new ThreadA();
            a.start();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    static public class Tools {
        public static ThreadLocalExt tl = new ThreadLocalExt();
    }
    static public class ThreadLocalExt extends ThreadLocal {
        @Override
        protected Object initialValue() {
            return new Date().getTime();
        }
    }

    static public class ThreadA extends Thread {

        @Override
        public void run() {
            try {
                for (int i = 0; i < 10; i++) {
                    System.out.println("在ThreadA線程中取值=" + Tools.tl.get());
                    Thread.sleep(100);
                }
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    }
}

從運(yùn)行結(jié)果可以看出子線程和父線程各自擁有各自的值。

運(yùn)行結(jié)果:

3.3 InheritableThreadLocal

ThreadLocal類固然很好,但是子線程并不能取到父線程的ThreadLocal類的變量,InheritableThreadLocal類就是解決這個(gè)問題的。

取父線程的值:

修改Test3.java的內(nèi)部類Tools 和ThreadLocalExt類如下:

 static public class Tools {
        public static InheritableThreadLocalExt tl = new InheritableThreadLocalExt();
    }
    static public class InheritableThreadLocalExt extends InheritableThreadLocal {
        @Override
        protected Object initialValue() {
            return new Date().getTime();
        }
    }

運(yùn)行結(jié)果:

取父線程的值并修改:

修改Test3.java的內(nèi)部類Tools 和InheritableThreadLocalExt類如下:

    static public class Tools {
        public static InheritableThreadLocalExt tl = new InheritableThreadLocalExt();
    }
    static public class InheritableThreadLocalExt extends InheritableThreadLocal {
        @Override
        protected Object initialValue() {
            return new Date().getTime();
        }

        @Override
        protected Object childValue(Object parentValue) {
            return parentValue + " 我在子線程加的~!";
        }
    }

運(yùn)行結(jié)果:

在使用InheritableThreadLocal類需要注意的一點(diǎn)是:如果子線程在取得值的同時(shí),主線程將InheritableThreadLocal中的值進(jìn)行更改,那么子線程取到的還是舊值。

參考:

《Java多線程編程核心技術(shù)》

《Java并發(fā)編程的藝術(shù)》

如果你覺得博主的文章不錯(cuò),歡迎轉(zhuǎn)發(fā)點(diǎn)贊。你能從中學(xué)到知識(shí)就是我最大的幸運(yùn)。

歡迎關(guān)注我的微信公眾號(hào):“Java面試通關(guān)手冊”(分享各種Java學(xué)習(xí)資源,面試題,以及企業(yè)級(jí)Java實(shí)戰(zhàn)項(xiàng)目回復(fù)關(guān)鍵字免費(fèi)領(lǐng)?。A硗馕覄?chuàng)建了一個(gè)Java學(xué)習(xí)交流群(群號(hào):174594747),歡迎大家加入一起學(xué)習(xí),這里更有面試,學(xué)習(xí)視頻等資源的分享。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/69099.html

相關(guān)文章

  • Java線程學(xué)習(xí)(七)并發(fā)編程中一些問題

    摘要:相比與其他操作系統(tǒng)包括其他類系統(tǒng)有很多的優(yōu)點(diǎn),其中有一項(xiàng)就是,其上下文切換和模式切換的時(shí)間消耗非常少。因?yàn)槎嗑€程競爭鎖時(shí)會(huì)引起上下文切換。減少線程的使用。很多編程語言中都有協(xié)程。所以如何避免死鎖的產(chǎn)生,在我們使用并發(fā)編程時(shí)至關(guān)重要。 系列文章傳送門: Java多線程學(xué)習(xí)(一)Java多線程入門 Java多線程學(xué)習(xí)(二)synchronized關(guān)鍵字(1) java多線程學(xué)習(xí)(二)syn...

    dingding199389 評(píng)論0 收藏0
  • Java線程學(xué)習(xí)(七)并發(fā)編程中一些問題

    摘要:因?yàn)槎嗑€程競爭鎖時(shí)會(huì)引起上下文切換。減少線程的使用。舉個(gè)例子如果說服務(wù)器的帶寬只有,某個(gè)資源的下載速度是,系統(tǒng)啟動(dòng)個(gè)線程下載該資源并不會(huì)導(dǎo)致下載速度編程,所以在并發(fā)編程時(shí),需要考慮這些資源的限制。 最近私下做一項(xiàng)目,一bug幾日未解決,總惶恐。一日頓悟,bug不可怕,怕的是項(xiàng)目不存在bug,與其懼怕,何不與其剛正面。 系列文章傳送門: Java多線程學(xué)習(xí)(一)Java多線程入門 Jav...

    yimo 評(píng)論0 收藏0
  • Java線程學(xué)習(xí)(二)synchronized關(guān)鍵字(2)

    摘要:關(guān)鍵字加到非靜態(tài)方法上持有的是對(duì)象鎖。線程和線程持有的鎖不一樣,所以和運(yùn)行同步,但是和運(yùn)行不同步。所以盡量不要使用而使用參考多線程編程核心技術(shù)并發(fā)編程的藝術(shù)如果你覺得博主的文章不錯(cuò),歡迎轉(zhuǎn)發(fā)點(diǎn)贊。 系列文章傳送門: Java多線程學(xué)習(xí)(一)Java多線程入門 Java多線程學(xué)習(xí)(二)synchronized關(guān)鍵字(1) java多線程學(xué)習(xí)(二)synchronized關(guān)鍵字(2) J...

    Batkid 評(píng)論0 收藏0
  • Java線程學(xué)習(xí)(四)等待/通知(wait/notify)機(jī)制

    摘要:運(yùn)行可運(yùn)行狀態(tài)的線程獲得了時(shí)間片,執(zhí)行程序代碼。阻塞的情況分三種一等待阻塞運(yùn)行的線程執(zhí)行方法,會(huì)把該線程放入等待隊(duì)列中。死亡線程方法執(zhí)行結(jié)束,或者因異常退出了方法,則該線程結(jié)束生命周期。死亡的線程不可再次復(fù)生。 系列文章傳送門: Java多線程學(xué)習(xí)(一)Java多線程入門 Java多線程學(xué)習(xí)(二)synchronized關(guān)鍵字(1) java多線程學(xué)習(xí)(二)synchronized關(guān)鍵...

    PiscesYE 評(píng)論0 收藏0
  • Java線程學(xué)習(xí)(二)synchronized關(guān)鍵字(1)

    摘要:轉(zhuǎn)載請備注地址多線程學(xué)習(xí)二將分為兩篇文章介紹同步方法另一篇介紹同步語句塊。如果兩個(gè)線程同時(shí)操作對(duì)象中的實(shí)例變量,則會(huì)出現(xiàn)非線程安全,解決辦法就是在方法前加上關(guān)鍵字即可。 轉(zhuǎn)載請備注地址: https://blog.csdn.net/qq_3433... Java多線程學(xué)習(xí)(二)將分為兩篇文章介紹synchronized同步方法另一篇介紹synchronized同步語句塊。系列文章傳送門...

    xuxueli 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<