1. 程式人生 > >面試總結(3):執行緒(Thread)的同步以及sleep() 、wait()的區別

面試總結(3):執行緒(Thread)的同步以及sleep() 、wait()的區別

前言

這幾天忙一點私事,今天回來趕緊把面試總結接著寫下去,這次來看看Thread的join()方法和sleep()和wait()方法的區別。

正文

執行緒同步

上一篇提到了執行緒同步的問題,主要是通過鎖的形式來進行執行緒間的喚醒和等待,執行緒之間的協作都是很密切的,有些時候我們需要執行緒之間順序執行要怎麼做呢???

方法有很多,除了之前講過的以外,我所瞭解的還有兩種方法:

一、Thread的join()方法

join()可以讓執行緒順序執行,他內部也是鎖的實現機制,看一下demo程式碼:

public class MainActivity extends AppCompatActivity
{
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); startFirstThread(); startSecondThread(); Log.e("lzp", "over"); } private void startFirstThread(){ Thread thread = new
Thread(){ @Override public void run() { for (int i = 0; i < 100; i++){ Log.e("lzp", "first:"+ i); if (i == 50){ try { sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } }; thread.start(); try
{ thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } } private void startSecondThread(){ Thread thread = new Thread(){ @Override public void run() { for (int i = 0; i < 100; i++){ Log.e("lzp", "second:"+ i); } } }; thread.start(); } }

程式碼比較簡單,就是同時開啟了兩條執行緒,如果沒有沒有join方法的話,肯定這兩條執行緒是同時執行的,log的結果也是亂的。

這裡寫圖片描述

然後在看一下第一條執行緒使用了join()之後的結果,為了突出顯示顯示join的作用,我還在oncreate也輸入了一句over。

這裡寫圖片描述

從log上來看,當第一條執行緒使用了join之後,主執行緒和第二條執行緒都暫停了,等待第一條執行緒執行完畢,在接著往下執行,說明呼叫了join之後,系統把所有的資源都給了第一條執行緒,就算是sleep(),也必要等待他執行完畢。

下面是第二條執行緒也join的結果:
這裡寫圖片描述

這裡寫圖片描述

所以join的作用就相當於阻塞掉除了當前執行緒以外的所有的執行緒(包括主執行緒),等待自己執行結束,並且遵守先來後到的排隊原則,先join的先執行,後join後執行,必須注意的是,最後的執行緒不能使用join,否則執行緒就全部在等待中,可以把最後一條不使用join的執行緒,當做此次排隊的結束。例如大家可以把demo中的oncreate中的最後的Log去掉,並且把第二條執行緒也join,看一下執行結果。

所以根據Thread的join()方法的特性,可以實現執行緒的同步。

二、單執行緒池

SingleThreadExecutor:是單執行緒池,他保證在自己執行緒池中提交的執行緒,按照提交的順序,順序執行且同時只有一條執行緒在跑。

也就是他只能執行一條執行緒,執行完了再跑下一條,例如我們平時執行緒操作資料庫,防止多執行緒併發,就會經常使用SingleThreadExecutor。

那我們來修改一下程式碼:

public class MainActivity extends AppCompatActivity {

    /**
     * 單執行緒池
     * */
    private Executor executor = Executors.newSingleThreadExecutor();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        startFirstThread();
        startSecondThread();
        Log.e("lzp", "over");

    }

    private void startFirstThread(){
        executor.execute(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++){
                    Log.e("lzp", "first:"+ i);
                    if (i == 50){
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        });
    }

    private void startSecondThread(){
        executor.execute(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++){
                    Log.e("lzp", "second:"+ i);
                }
            }
        });
    }
}

demo中順序提交了兩條執行緒,並且第一條執行緒還sleep了一秒,看一下執行結果:

這裡寫圖片描述

執行緒1和執行緒2確實是順序執行的,就算是sleep也不行,但是同時也發現執行緒池不能把主執行緒的執行順序也包括進來,而這一點join可以做到。

ok,那執行緒同步就到此結束了,當然還有一些另類的方法,例如通過handler來發送訊息或者是其他的方法,這裡不做介紹了,需求是死的,但是套路是活的,有更好的方法,可以留言,大家一起交流。

sleep() 、wait()的區別

這個問題當時是把我弄蒙圈了,因為我第一反應不知道為啥他倆要比較,因為覺得他倆好像沒多大的關係,後來在面試官的提示下我才明白他的意思,在這裡做個總結:

1、sleep()屬於Thread,wait()屬於 Class。

2、sleep()僅僅是睡眠,不涉及到鎖的釋放問題,睡眠時間結束自動恢復到執行狀態。
wait()綁定了某個物件的鎖,等待該物件的notify(),notifyAll()來喚醒自己,等待的時間是未知的,甚至出現死鎖。

那sleep()和wait()會釋放cpu嗎?

這個問題在網上是五花八門,剛才我們已經使用了sleep(),就可以得到以下結論:

非執行緒池中
1、sleep()中會釋放cpu,讓cpu去執行其他的執行緒,睡眠時間結束,在重新佔用cpu執行。(第一個demo的程式碼,執行緒1在睡眠中,直接把cpu交給了執行緒2)

2、如果呼叫了join方法(),相當於沒有釋放cpu,因為其他執行緒無法得到執行。(join方法的demo,順序執行,sleep無影響)。

執行緒池中
跟非執行緒池中一樣,會把資源讓給同時執行的執行緒,但是仍然會佔用執行緒池的位置,例如demo中的單執行緒池,儘管sleep,但是位置仍然佔用,所以下一個執行緒不會得到執行。

總結:無論怎用sleep都會釋放cpu,但是線上程池中會佔用位置。

那麼再來看看wait,wait跟sleep沒有太大差別,cpu肯定是要釋放出去的,那麼他會佔用執行緒池中的位置嗎?

修改一下程式碼:

private void startFirstThread(){
        executor.execute(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++){
                    Log.e("lzp", "first:"+ i);
                    if (i == 50){
                        try {
                            synchronized (this){
                                wait();
                            }
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        });
    }

我在第一個執行緒中,直接wait,看一下log:

這裡寫圖片描述

log在50的時候停止了,第二條執行緒沒有執行,說明wait也會佔用執行緒池中的位置。

總結

首先我們聊了聊執行緒同步的問題,實現執行緒順序執行有很多種方法,就看大家自己的思考了,腦洞的同時也得思考合理性和實用性,好壞就不做評判了。

然後去討論一下sleep和wait的區別,總結:他倆都是要釋放cpu的,並且線上程池中會佔用位置。如果你也遇到了這樣的問題,就好辦多了。

OK,那這一篇就結束了,有什麼問題和建議歡迎留言。

相關推薦

面試總結3執行Thread同步以及sleep() wait區別

前言 這幾天忙一點私事,今天回來趕緊把面試總結接著寫下去,這次來看看Thread的join()方法和sleep()和wait()方法的區別。 正文 執行緒同步 上一篇提到了執行緒同步的問題,主要是通過鎖的形式來進行執行緒間的喚醒和等待,執行緒之間的

【Java基礎_執行篇_第一篇)】繼承Thread;實現runnable;sleepwait用法和區別Thread和Runnable區別執行停止

一、執行緒兩種實現 1.繼承Thread類: (1)【直接在主類繼承】 package org; // 繼承 Thread 類 public class TestThreadofExt extends Thread { private static int count =

Java併發程式設計3執行掛起恢復與終止的正確方法含程式碼

JAVA大資料中高階架構 2018-11-06 14:24:56掛起和恢復執行緒Thread 的API中包含兩個被淘汰的方法,它們用於臨時掛起和重啟某個執行緒,這些方法已經被淘汰,因為它們是不安全的,不穩定的。如果在不合適的時候掛起執行緒(比如,鎖定共享資源時),此時便可能會發生死鎖條件——其他執行緒在等待該

C#執行3執行暫停

執行緒暫停是讓某一個執行緒先休眠一段時間,在這段時間內,該執行緒不佔用系統資源 用一個例子說明執行緒休眠,除了主函式還有另一個執行緒,主函式會輸出從11到19的數字,而執行緒會每隔兩秒輸出從1到9的數 (一):首先建立控制檯程式 在預處理部分寫入 using static Syste

OKHttp 3.10原始碼解析執行池和任務佇列

OKhttp是Android端最火熱的網路請求框架之一,它以高效的優點贏得了廣大開發者的喜愛,下面是OKhttp的主要特點: 1.支援HTTPS/HTTP2/WebSocket 2.內部維護執行緒池佇列,提高併發訪問的效率 3.內部維護連線池,支援多路複用,減少連線建立開銷 4.

Java併發程式設計2執行中斷含程式碼

使用interrupt()中斷執行緒當一個執行緒執行時,另一個執行緒可以呼叫對應的Thread物件的interrupt()方法來中斷它,該方法只是在目標執行緒中設定一個標誌,表示它已經被中斷,並立即返回。這裡需要注意的是,如果只是單純的呼叫interrupt()方法,執行緒並沒有實際被中斷,會繼續往下執行。

C#執行4執行等待

執行緒等待,或者說叫等待執行緒。其語句是  執行緒名.Join()   。按照我的理解,這個語句其實是告訴系統程式,這個執行緒很重要,你必須使用全部的計算資源供他計算,等他計算結束了之後再回到這個位置。     舉例來說,下面這個程式就用了執行緒等

執行執行開啟方式與多執行threading模組

目錄 執行緒的建立Threading.Thread類 1)執行緒的建立 2)多執行緒與多程序 3)Thread類的其他方法 4)守護執行緒 multiprocess模組的完全模仿了threading模組的介面,二者在使用層面,有很大的相似性,因而不再詳細介紹(官方連結)

併發程式設計執行基礎執行之間的共享與協作

一、基礎概念 1.1 CPU核心數、執行緒數 **兩者的關係:**cpu的核心數與執行緒數是1:1的關係,例如一個8核的cpu,支援8個執行緒同時執行。但在intel引入超執行緒技術以後,cpu與執行緒數的關係就變成了1:2。此外在開發過程中並沒感覺到執行緒的限制,那是因為cpu

java多執行:建立執行的三種方式以及優缺點總結

一、Java中建立執行緒主要有三種方式: 1、繼承Thread類建立執行緒類 步驟: (1)定義Thread類的子類,並重寫該類的run方法,該run方法的方法體就代表了執行緒要完成的任務。因此把run()方法稱為執行體。 (2)建立Thread子類的例項,即建立了執行緒物件。

Java併發二十一執行池實現原理 Java併發十八阻塞佇列BlockingQueue Java併發十八阻塞佇列BlockingQueue Java併發程式設計執行池的使用

一、總覽 執行緒池類ThreadPoolExecutor的相關類需要先了解:  (圖片來自:https://javadoop.com/post/java-thread-pool#%E6%80%BB%E8%A7%88) Executor:位於最頂層,只有一個 execute(Runnab

Java併發二十一執行池實現原理

Java併發(二十一):執行緒池實現原理 一、總覽 執行緒池類ThreadPoolExecutor的相關類需要先了解:  (圖片來自:https://javadoop.com/post/java-thread-pool#%E6%80%BB%E8%A7%88) E

Java多執行執行基礎及建立

(一)、執行緒的生命週期 新建狀態: 使用 new 關鍵字和 Thread 類或其子類建立一個執行緒物件後,該執行緒物件就處於新建狀態。它保持這個狀態直到程式 start() 這個執行緒。 就緒狀態: 當執行緒物件呼叫了start()方法之後,該執行緒就進入就緒

執行學習執行的互斥

生產者與消費者模型 在講同步和互斥之前,首先了解一下消費者模型 什麼是消費者模型? 消費者模型是一個描述消費者和生產者之間的關係的一個模型,生產者和消費者模型指的是在一個場所中,兩個角色,三種關係 消費者和消費者之間——互斥 消費者之間是競爭關係,比如有一個

理解JVM執行安全和鎖優化

執行緒安全的實現方法 互斥同步 互斥是因,同步是果;互斥是方法,同步是目的。 synchronized關鍵字 synchronized關鍵字是基本的互斥同步手段。它在編譯後會在同步程式碼塊前後加入2條位元組碼指令:monitorenter和mo

執行池原理執行池的使用

這篇文章通過介紹執行緒池的常見用法,總結前面學習到的內容。 主要包括 ThreadPoolExecutor的使用 ScheduledThreadPoolExecutor的使用 ExecutorCompletionService的使用 1. 統計某個區間

java多執行1執行的建立和多執行的安全問題

前言 java多執行緒多用於服務端的高併發程式設計,本文就java執行緒的建立和多執行緒安全問題進行討論。 正文 一,建立java執行緒 建立java執行緒有2種方式,一種是繼承自Thread類,另一種是實現Runnable介面。由於java只支援單

EventBus原始碼分析執行模型分析2.4版本

EventBus有四種執行緒模型 PostThread模式不需執行緒切換,直接在釋出者執行緒進行事件處理。 MainThread模式分類討論:釋出者執行緒是主執行緒則直接呼叫事件處理方法,否則通過Handler進行執行緒切換,切換到主執行緒處理事件,該模

執行學習執行間的資料共享

資料不共享的情況 public class MyThread04 extends Thread{ private int count=5; public MyThread04(String threadName) { this.setName(threadName); }

JAVA多執行執行安全與資料同步 synchronizedThis MonitorClass Monitor

      本章首先從一個簡單的例子入手,講解了資料同步的概念,以及會引發資料不一致性問題的情況,然後非常詳細地介紹了synchronized關鍵字以及與其對應的JVM指令。本章的最後還分析了幾種可能引起程式進入死鎖的原因,以及如何使用工具進行診斷,執行緒安全與資料同步