【從零開始學(xué)Java筆記】多線程

大家可以關(guān)注作者的賬號(hào),關(guān)注從零開始學(xué)Java筆記文集。也可以根據(jù)目錄前往作者的博客園博客進(jìn)行學(xué)習(xí)。本片文件將基于黑馬程序員就業(yè)班視頻進(jìn)行學(xué)習(xí)以及資料的分享,并記錄筆記和自己的看法。歡迎大家一起學(xué)習(xí)和討論。

【從零開始學(xué)Java筆記】目錄

進(jìn)程和線程的區(qū)別

進(jìn)程:是執(zhí)行中一段程序,即一旦程序被載入到內(nèi)存中并準(zhǔn)備執(zhí)行,它就是一個(gè)進(jìn)程。進(jìn)程是表示資源分配的的基本概念,又是調(diào)度運(yùn)行的基本單位,是系統(tǒng)中的并發(fā)執(zhí)行的單位。
線程:?jiǎn)蝹€(gè)進(jìn)程中執(zhí)行中每個(gè)任務(wù)就是一個(gè)線程。線程是進(jìn)程中執(zhí)行運(yùn)算的最小單位。
一個(gè)進(jìn)程可以有一個(gè)線程,也可以有多個(gè)線程

單線程和多線程的優(yōu)缺點(diǎn)

單線程:安全性高,但是效率低
多線程:安全性低,效率高
多線程案例: 360,迅雷等

Thread類

創(chuàng)建線程的方法一

先創(chuàng)建一個(gè)類,繼承Thread類,并且重寫run方法。

public class MyThread extends Thread{
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(getName()+i);
        }
    }
}

在主函數(shù)里面調(diào)用MyThread類,然后使用start()方法即可調(diào)用。

public class ThreadDemo {
    public static void main(String[] args) {
        //創(chuàng)建一個(gè)線程
        MyThread mt = new MyThread();
        mt.setName("Thread-1:");
        mt.start();
        
        //創(chuàng)建另一個(gè)線程
        MyThread mt2 = new MyThread();
        mt2.setName("Thread-2:");
        mt2.start();
    }

}

輸出結(jié)果(部分)如下



可以看出線程一和線程二交替出現(xiàn),這是因?yàn)橛?jì)算機(jī)處理兩個(gè)同時(shí)運(yùn)行的線程時(shí),用極短的時(shí)間在兩個(gè)線程間切換,隨機(jī)調(diào)用。但速度極快,無(wú)法察覺到。

創(chuàng)建線程的方法二

創(chuàng)建線程的另一種方法是聲明實(shí)現(xiàn) Runnable 接口的類。該類然后實(shí)現(xiàn) run 方法。然后可以分配該類的實(shí)例,在創(chuàng)建 Thread 時(shí)作為一個(gè)參數(shù)來(lái)傳遞并啟動(dòng)。

public class MyThread2 implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + i);
        }
    }

}
public class ThreadDemo2 {
    public static void main(String[] args) {
        MyThread2 mt = new MyThread2();
        Thread t = new Thread(mt);
        t.setName("Thread-1:");
        t.start();
        
        MyThread2 mt2 = new MyThread2();
        Thread t2 = new Thread(mt);
        t2.setName("Thread-2:");
        t2.start();
        
    }

}

輸出結(jié)果(部分)與之前的輸出結(jié)果相似


模擬火車站售票

1.先創(chuàng)建線程類
要求:100張票,持續(xù)售票,票數(shù)為0停止售票。

public class ThreadTicket implements Runnable {

    private static int ticketNum = 100;

    @Override
    public void run() {
        while (true) {
            if (ticketNum > 0) {
                System.out.println(Thread.currentThread().getName() + ":" + ticketNum--);
            }
        }

    }

    public static int getTicketnum() {
        return ticketNum;
    }

}

主函數(shù)

public class ThreadTicketDemo {
    public static void main(String[] args) {
        ThreadTicket tt = new ThreadTicket();
        Thread t1 = new Thread(tt);
        t1.setName("售票口1");
        t1.start();
        
    }

}

輸出結(jié)果(部分)


火車站不可能只有一個(gè)售票口,所以多加幾個(gè)線程

public class ThreadTicketDemo {
    public static void main(String[] args) {
        ThreadTicket tt = new ThreadTicket();
        Thread t1 = new Thread(tt);
        t1.setName("售票口1");
        t1.start();
        
        Thread t2 = new Thread(tt);
        t2.setName("售票口2");
        t2.start();
        
        Thread t3 = new Thread(tt);
        t3.setName("售票口3");
        t3.start();
    }

}

輸出結(jié)果(部分)



細(xì)心的朋友應(yīng)該發(fā)現(xiàn)最后售票是十分不規(guī)律的,例如售票口2已經(jīng)在售賣最后一張票的時(shí)候,售票口3還在售賣第十一張票,其實(shí)這是符合生活規(guī)律的,大家思考一下自己買票的經(jīng)歷。因?yàn)閏pu調(diào)用每個(gè)線程都是隨機(jī)的,而線程的運(yùn)行也是需要時(shí)間的,售票口3在售賣第十一張票的時(shí)候,cpu不斷調(diào)用售票口2,持續(xù)售票。

為了讓程序更明顯一點(diǎn),我們?cè)诔绦蛑屑尤雜leep()

public class ThreadTicket implements Runnable {

    private static int ticketNum = 100;

    @Override
    public void run() {
        while (true) {
            if (ticketNum > 0) {

                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

                System.out.println(Thread.currentThread().getName() + ":" + ticketNum--);
            }
        }

    }

    public static int getTicketnum() {
        return ticketNum;
    }

}

再次輸出



首先可以發(fā)現(xiàn)程序明顯變慢,然后發(fā)現(xiàn)有一些錯(cuò)誤,第六張票售出兩次,并且沒有票的時(shí)候還售出一張,這是因?yàn)楫?dāng)票數(shù)還是正常的情況下,例如一張,其中一個(gè)線程進(jìn)行判斷,并進(jìn)入休息。另一個(gè)進(jìn)程也進(jìn)入判斷。這時(shí)兩個(gè)進(jìn)程同時(shí)通過判斷,休息后,同時(shí)進(jìn)行了輸出,就會(huì)出現(xiàn)這樣的錯(cuò)誤。

那么如何解決這個(gè)問題呢?
synchronized:同步(鎖),可以修飾代碼塊和方法,被修飾的代碼塊和方法一旦被某個(gè)線程訪問,則直接鎖住,其他的線程將無(wú)法訪問。

方法一:
同步代碼塊:

synchronized(鎖對(duì)象){

}

注意:鎖對(duì)象需要被所有的線程所共享
方法二:
同步方法:使用關(guān)鍵字synchronized修飾的方法,一旦被一個(gè)線程訪問, 則整個(gè)方法全郁鎖住,其他線程則無(wú)法訪問。

注意:
非靜態(tài)同步方法的鎖對(duì)象是this
靜態(tài)的同步方法的鎖對(duì)象是當(dāng)前類的字節(jié)碼對(duì)象

在這里如果遇到了加鎖后出現(xiàn)了只有一個(gè)線程運(yùn)行的情況,可以參考
synchronized同步方法\塊只有一個(gè)線程執(zhí)行\(zhòng)運(yùn)行

同步的特點(diǎn):
同步:安全性高,效率低
非同步:效率高,但是安全性低

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一擴(kuò)展javalangThread類二實(shí)現(xiàn)javalangRunnable接口三Thread和Runnable的區(qū)...
    和帥_db6a閱讀 594評(píng)論 0 1
  • Java多線程學(xué)習(xí) [-] 一擴(kuò)展javalangThread類 二實(shí)現(xiàn)javalangRunnable接口 三T...
    影馳閱讀 3,112評(píng)論 1 18
  • 本文主要講了java中多線程的使用方法、線程同步、線程數(shù)據(jù)傳遞、線程狀態(tài)及相應(yīng)的一些線程函數(shù)用法、概述等。 首先講...
    李欣陽(yáng)閱讀 2,600評(píng)論 1 15
  • 一、進(jìn)程和線程 進(jìn)程 進(jìn)程就是一個(gè)執(zhí)行中的程序?qū)嵗總€(gè)進(jìn)程都有自己獨(dú)立的一塊內(nèi)存空間,一個(gè)進(jìn)程中可以有多個(gè)線程。...
    阿敏其人閱讀 2,711評(píng)論 0 13
  • 1 多線程 1.1 多線程介紹 ??學(xué)習(xí)多線程之前,我們先要了解幾個(gè)關(guān)于多線程有關(guān)的概念。??進(jìn)程:進(jìn)程指正在運(yùn)行...
    圣堂刺客_x閱讀 399評(píng)論 0 0

友情鏈接更多精彩內(nèi)容