1. 程式人生 > >JAVA多執行緒Thread VS Runnable詳解

JAVA多執行緒Thread VS Runnable詳解

要求

    • 必備知識

      本文要求基本瞭解JAVA程式設計知識。

    • 開發環境

      windows 7/EditPlus

    • 演示地址

      原始檔

程序與執行緒

程序是程式在處理機中的一次執行。一個程序既包括其所要執行的指令,也包括了執行指令所需的系統資源,不同程序所佔用的系統資源相對獨立。所以程序是重量級的任務,它們之間的通訊和轉換都需要作業系統付出較大的開銷。

執行緒是程序中的一個實體,是被系統獨立排程和分派的基本單位。執行緒自己基本上不擁有系統資源,但它可以與同屬一個程序的其他執行緒共享程序所擁有的全部資源。所以執行緒是輕量級的任務,它們之間的通訊和轉換隻需要較小的系統開銷。

Java支援多執行緒程式設計,因此用Java編寫的應用程式可以同時執行多個任務。Java的多執行緒機制使用起來非常方便,使用者只需關注程式細節的實現,而不用擔心後臺的多工系統。

Java語言裡,執行緒表現為執行緒類。Thread執行緒類封裝了所有需要的執行緒操作控制。在設計程式時,必須很清晰地區分開執行緒物件和執行執行緒,可以將執行緒物件看作是執行執行緒的控制面板。線上程物件裡有很多方法來控制一個執行緒是否執行,睡眠,掛起或停止。執行緒類是控制執行緒行為的唯一的手段。一旦一個Java程式啟動後,就已經有一個執行緒在執行。可通過呼叫Thread.currentThread方法來檢視當前執行的是哪一個執行緒。

執行緒建立的兩種方法

JAVA中建立執行緒可以通過繼承Thread類和實現Runnable介面來建立一個執行緒。Runnable方式可以避免Thread 方式由於JAVA單繼承特性帶來的缺陷。Runnable的程式碼可以被多個執行緒(Thread例項)共享,適合於多個執行緒處理同一資源的情況。

  • 繼承Thread類

class MyThread extends Thread{
    .....
    @Override
    public void run(){

    }

}

MyThread mt=new MyThread();
mt.start();
  • 實現Runnable介面

class MyThread implements Runnable{
    ....
    @Override
    public void run(){

    }
}

MyThread mt=new MyThread();
Thread td=new Thread(mt);
sd.start();

Thread&Runnable分別模擬賣火車票

  • Thread方式

class MyThread extends Thread
{
    private int ticketsCont=5; //一共有5張火車票

    private String name; //視窗, 也即是執行緒的名字

    public MyThread(String name){
        this.name=name;
    }

    @Override
    public void run(){
        
        while(ticketsCont>0){
            ticketsCont--; //如果還有票,就賣掉一張票
            System.out.println(name+"賣掉了1張票,剩餘票數為:"+ticketsCont);
        }
        
    }
}

public class TicketsThread
{
    public static void main(String args[]){
        
        //建立三個執行緒,模擬三個視窗賣票
        MyThread mt1=new MyThread("視窗1");
        MyThread mt2=new MyThread("視窗2");
        MyThread mt3=new MyThread("視窗3");

        //啟動三個執行緒,也即是視窗,開始賣票
        mt1.start();
        mt2.start();
        mt3.start();

    }
}
  • Runnable方式

class MyThread2 implements Runnable
{
    private int ticketsCont=1000; //一共有5張火車票
    
    @Override
    public void run(){
        
            
            while(true){
                 synchronized(this){
                    if(ticketsCont<=0){
                        break;
                    }
                    ticketsCont--; //如果還有票,就賣掉一張票
                    
                    System.out.println(Thread.currentThread().getName()+"賣掉了1張票,剩餘票數為:"+ticketsCont);
                    
                    /*try{
                        Thread.sleep(50);  //通過阻塞程式來檢視效果
                    }
                    catch(Exception e){
                        System.out.println(e);
                    }*/

                }
            }
        
    }



    /*@Override  //不加同步鎖
    public void run(){
        while(ticketsCont>0){
            ticketsCont--; //如果還有票,就賣掉一張票
            System.out.println(Thread.currentThread().getName()+"賣掉了1張票,剩餘票數為:"+ticketsCont);
        }
    }*/
}

public class TicketsRunnable
{
    public static void main(String args[]){
        
        MyThread2 mt=new MyThread2();
        //建立三個執行緒來模擬三個售票視窗
        Thread th1=new Thread(mt,"視窗1");
        Thread th2=new Thread(mt,"視窗2");
        Thread th3=new Thread(mt,"視窗3");

        //啟動三個執行緒,也即是三個視窗,開始賣票
        th1.start();
        th2.start();
        th3.start();
        

    }
}

執行緒的生命週期

2015-03-12_141728

  • 建立:新建一個執行緒物件,如Thread thd=new Thread()
  • 就緒:建立了執行緒物件後,呼叫了執行緒的start()方法(此時執行緒知識進入了執行緒佇列,等待獲取CPU服務 ,具備了執行的條件,但並不一定已經開始運行了)
  • 執行:處於就緒狀態的執行緒,一旦獲取了CPU資源,便進入到執行狀態,開始執行run()方法裡面的邏輯
  • 終止:執行緒的run()方法執行完畢,或者執行緒呼叫了stop()方法,執行緒便進入終止狀態
  • 阻塞:一個正在執行的執行緒在某些情況系,由於某種原因而暫時讓出了CPU資源,暫停了自己的執行,便進入了阻塞狀態,如呼叫了sleep()方法

執行緒的分類

  • 使用者執行緒:執行在前臺,執行具有的任務程式的主執行緒,連線網路的子執行緒等都是使用者執行緒
  • 守護執行緒:執行在後頭,為其他前臺執行緒服務。一旦所有使用者執行緒都結束執行,守護執行緒會隨JVM一起結束工作。可以通過呼叫Thread類的setDaemon(true)方法來設定當前的執行緒為守護執行緒,該方法必須在start()方法之前呼叫,否則會丟擲 IllegalThreadStateException異常。在守護執行緒中產生的新執行緒也是守護執行緒。不是所有的任務都可以分配給守護執行緒來執行,比如讀寫操作或者計算邏輯。

守護執行緒測試案例

2015-03-12_145001

場景:一個主執行緒,一個守護執行緒,守護執行緒會在很長一段時間內向本地檔案中寫入資料,主執行緒進入阻塞狀態等待使用者的輸入,一旦確認了使用者的輸入阻塞就會解除掉,主執行緒繼續執行直到結束,守護執行緒也會隨虛擬機器一同結束。

import java.io.*;
import java.util.Scanner;

class Daemon  implements Runnable
{
    @Override
    public void run(){
        System.out.println("進入守護執行緒");
        try{
            writeToFile();
        }
        catch(Exception e){
            e.printStackTrace();
        }

        System.out.println("退出守護執行緒");
    }


    private void writeToFile() throws Exception{
            File filename=new File("F:/慕課網(imooc)/細說多執行緒之Thread VS Runnable/daemon.txt");
            OutputStream os=new FileOutputStream(filename,true);
            int count=0;
            while(count<999){
                os.write(("\r\nword"+count).getBytes());
                System.out.println("守護執行緒"+Thread.currentThread().getName()+"向檔案中寫入word"+count++);
                Thread.sleep(1000);
            }
    }
}

public class DaemonThreadDemo
{
    public static void main(String args[]){
        System.out.println("進入主執行緒"+Thread.currentThread().getName());
        Daemon daemonThread=new Daemon();
        Thread thread =new Thread(daemonThread);
        thread.setDaemon(true);
        thread.start();

        Scanner sc=new Scanner(System.in);
        sc.next();

        System.out.println("退出主執行緒"+Thread.currentThread().getName());

        
    }
}

測試結果

2015-03-12_145755

使用jstack生成執行緒快照

jstack工具到jdk安裝目錄bin資料夾下。jstack能生成JVM當前時刻執行緒的快照(threaddump, 即當前程序中所有執行緒的資訊)。幫助定位程式問題出現的原因,如長時間停頓、CPU佔用率過高等。

使用方法

jstack [-l] <pid> : [-l]可有可無,表示關於鎖的二位資訊;<pid>表示程序ID。

2015-03-12_151225

總結

建議使用Runnable這種方式建立執行緒。 程式中的同一資源指的是同一個Runnable物件。安全的賣票程式中需要加入同步synchronized。

如以上文章或連結對你有幫助的話,別忘了在文章結尾處輕輕點選一下 “還不錯”按鈕或到頁面右下角點選 “贊一個” 按鈕哦。你也可以點選頁面右邊“分享”懸浮按鈕哦,讓更多的人閱讀這篇文章。

相關推薦

JAVA執行Thread VS Runnable

要求 必備知識 本文要求基本瞭解JAVA程式設計知識。 開發環境 windows 7/EditPlus 演示地址 原始檔 程序與執行緒 程序是程式在處理機中的一次執行。一個程序既包括其所要執行的指令,也包括了執行指令所需的系統資源,不同程序所

java執行ThreadRunnable的區別與使用深入理解

首先,多執行緒的實現方式兩種:一種是繼承Thread類,另一種是實現Runnable介面。 那麼這兩種方法的區別何在?該如何選擇? 第一:他們之間的關係 檢視J2EE的API看到 Thread類中:  public class Thread extends Objec

Java執行Condition介面原理

Condition介面提供了類似Object的監視器方法,與Lock配合可以實現等待/通知模式,但是這兩者在使用方式以及功能特性上還是有差別的 Condition介面詳解 Condition定義了等待/通知兩種型別的方法,當前執行緒呼叫這些方法時,需要提前獲

Java執行同步和非同步

1. 多執行緒併發時,多個執行緒同時請求同一資源,必然導致此資源的資料不安全。 2. 執行緒池 在WEB服務中,對於web伺服器的響應速度必須儘可能的快,這就容不得在使用者提交請求按鈕後,再建立執行緒提供服務。為了減少使用者的等待時間,執行緒必須預先建立,放線上程池中,執行

入坑JAVA執行併發(八)ThreadLocal使用和原理

  ThreadLocal是一個用於儲存多執行緒變數的類,它可以把執行緒與設定的值對應起來,因為它為變數在每個執行緒都建立了一個副本。訪問的時候每個執行緒只能訪問到自己的副本變數。 例項 看如下程式碼: public class Main {

Java 執行之synchronized關鍵字

package com.example; /** * Created by 晁東洋 on 2017/5/27. */ public class MyThreadClass { public static void main(String args[]){ Exampletest

java執行與併發程式設計

一、多執行緒1、作業系統有兩個容易混淆的概念,程序和執行緒。程序:一個計算機程式的執行例項,包含了需要執行的指令;有自己的獨立地址空間,包含程式內容和資料;不同程序的地址空間是互相隔離的;程序擁有各種資源和狀態資訊,包括開啟的檔案、子程序和訊號處理。執行緒:表示程式的執行流程

Java執行-Thread.yield

http://blog.csdn.net/dabing69221/article/details/17426953 Thread.yield( )方法: 使當前執行緒從執行狀態(執行狀態)變為可執行態(就緒狀態)。cpu會從眾多的可執行態裡選擇,也就是說,當前也就

java 執行Thread

Thread類之前在部落格簡單介紹了下,本篇重點介紹幾個常用方法: 先看構造方法: Thread() 建立新的執行緒物件 Thread(String name) 基於指定的名字建立一個執行緒物件 Thread(Runnable target)基於Runnable介面實現類的例項(可以

(CSDN遷移) JAVA執行實現-實現Runnable介面

實現Runnable介面  implements Runnable 重寫run()方法 @Override public void run(){//TODO} 建立執行緒物件: Thread thread1 = new Thread(new Implement

java執行Thread

認識多執行緒,首先要從程式是如何在CPU中進行排程說起,眾所周知,我們自己的筆記本中只有一個CPU,這個CPU在你電腦開機的時候開始就執行著許多程式,比如作業系統,可是一個CPU在某一單位時間只能執行一個程式,而電腦中這麼多的程式CPU是如何安排工作的呢?這就涉及到了併發的概念. 併發:有

java執行-Thread的yield方法

yield表示當前執行緒申請交出執行權,但並不是一定會交出,依賴於系統的執行緒排程。 因此該方法並不穩定。 class Test { public static void main(String[] args) throws InterruptedException { Te

java執行-Thread的sleep方法

public static native void sleep(long millis) throws InterruptedException; sleep是本地靜態方法。sleep的作用是讓執行緒進入TIME_WAITING狀態,引數是多少毫秒。 class Test { pu

Java執行-----Thread常用方法

   1.public Thread(Runnable target,String name) 建立一個有名稱的執行緒物件 package com.thread.mothed; public class ThreadMethod {

java執行-Thread兩個執行交換資料Exchanger

/** * 2017-4-21 * author:饒為 * Administrator */package Thread;import java.util.concurrent.Exchanger;/** * 2017-4-21 * author:饒為 * Administrator */public cla

java執行Thread.Join()和Thread.Sleep()

其實我想要   一種美夢睡不著   一種心臟的狂跳   瓦解界線不被撂倒 奔跑 依靠   我心中最想要   看你看過的浪潮   陪你放肆地年少   ——林俊杰【偉大的渺小】 ------------

Java 執行異常捕獲Runnable實現

1、背景:         Java 多執行緒異常不向主執行緒拋,自己處理,外部捕獲不了異常。所以要實現主執行緒對子執行緒異常的捕獲。 2、工具:         實現Runnable介面的LayerInitTask類,ThreadException類,執行緒安全的Vect

Java 執行——Thread類和Runable介面

在java中可有兩種方式實現多執行緒,一種是繼承Thread類,一種是實現Runnable介面; Thread類是在java.lang包中定義的。一個類只要繼承了Thread類同時覆寫了本類中的 run()方法就可以實現多執行緒操作了,但是一個類只能繼承一個父類,這是此方法

執行之Future使用

什麼是Future Future是一個未來物件,裡面儲存這執行緒處理結果,它像一個提貨憑證,拿著它你可以隨時去提取結果 什麼時候使用 在兩種情況下,離開Future幾乎很難辦。 一種情況是拆分訂單,比如你的應用收到一個批量訂單,此時如果要求最快的處理訂單,那麼需要併發

Android 執行之HandlerThread 完全

  之前對執行緒也寫過幾篇文章,不過倒是沒有針對android,因為java與android線上程方面大部分還是相同,不過本篇我們要介紹的是android的專屬類HandlerThread,因為HandlerThread在設定思想上還是挺值得我們學習的,那麼我們下面來