亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

一篇文章帶你入門Java多線程

 更新時間:2021年08月05日 09:57:05   作者:再來半包  
這篇文章主要介紹了java多線程編程實例,分享了幾則多線程的實例代碼,具有一定參考價值,加深多線程編程的理解還是很有幫助的,需要的朋友可以參考下

進程

1、進程是指運行中的程序,比如我們使用qq,就啟動了一個進程,操作系統(tǒng)就會為該進程分配內(nèi)存空間。當(dāng)我們使用迅雷,又啟動了一個進程,操作系統(tǒng)將為迅雷分配新的內(nèi)存空間

2、進程是程序的一次執(zhí)行過程,或是正在運行的一個程序。是動態(tài)過程:有它自身的產(chǎn)生、存在和消亡的過程

其他相關(guān)概念

1、單線程:同一個時刻,只允許執(zhí)行一個線程

2、多線程:同一時刻,可以執(zhí)行多個線程,比如:一個qq進程,可以同時打開多個聊天窗口,一個迅雷進程,可以同時下載多個文件

3、并發(fā):同一時刻,多個任務(wù)交替執(zhí)行,造成一種“貌似同時”的錯覺,簡單的說,單核cpu實現(xiàn)的多任務(wù)就是并發(fā)

4、并行:同一時刻,多個任務(wù)同時進行。多核cpu可以實現(xiàn)并行。并發(fā)和并行:如果開的程序太多,有可能也會觸發(fā)并發(fā)

創(chuàng)建線程的兩種方式

1、繼承Thread類,重寫run方法

實例:

//該線程每隔1秒鐘。在控制臺輸出"喵喵",打印8次后結(jié)束線程
public class Thread01 {
    public static void main(String[] args) {
        //創(chuàng)建一個cat對象,可以當(dāng)作線程使用
        Cat cat=new Cat();
        cat.start();//啟動線程
    }
}
//1、當(dāng)一個類繼承了 Thread 類 ,該類就可以當(dāng)作線程使用
//2、我們會重寫run方法,寫上自己的業(yè)務(wù)代碼
//3、run  Thread 類 實現(xiàn)了 Runnable 接口的run方法
class Cat extends Thread{
    int times=0;
    @Override
    public void run() {  //重寫run方法,寫上自己的業(yè)務(wù)邏輯

        while(true) {
            System.out.println("喵喵"+ ++times);
            //讓該線程休眠1秒鐘
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (times==8){//設(shè)置打印次數(shù)
                break;
            }
        }
    }
}

為什么使用start()方法而不直接使用run()方法

因為run()方法就是一個普通的方法,沒有真正的啟動一個線程,就會把run方法執(zhí)行完畢,才向下執(zhí)行

start()方法底層

(1)
public synchronized void start() {
  start0();  
}
//start0();是start中最主要的方法
(2)
//start0(); 是本地方法,是JVM調(diào)用,底層是C/C++實現(xiàn)
//真正實現(xiàn)多線程的效果,是start0(),而不是run,也可以說在start0()本地方法中去調(diào)用了Run()方法

在這里插入圖片描述

2、實現(xiàn)Runnable接口,重寫run方法

public class Thread03 {
    public static void main(String[] args) {
        T1 t1 = new T1();
        T2 t2 = new T2();
        Thread thread1=new Thread(t1);
        Thread thread2=new Thread(t2);
        thread1.start();
        thread2.start();
    }
}
class T1 implements Runnable{
    int count=0;
    @Override
    public void run() {
        while (true) {
            //每隔1秒輸出"hello,world",輸出10次
            System.out.println("hello,world " + ++count + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (count==50){
                break;
            }
        }
    }
}
class T2 implements Runnable{
    int count=0;
    @Override
    public void run() {
        while (true) {
            //每隔1秒輸出"hello,world",輸出10次
            System.out.println("hi " + ++count + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (count==60){
                break;
            }
        }
    }

繼承Thread 和 實現(xiàn)Rnnable的區(qū)別

1、從Java的設(shè)計來看,通過繼承Thread或者實現(xiàn)Runnable接口來創(chuàng)建線程本質(zhì)上沒有區(qū)別,從jdk幫助文檔我們可以看到Thread類本身就實現(xiàn)了Runnable接口

2、實現(xiàn)Runnable接口方式更加適合多個線程共享一個資源的情況,并且避免了單繼承的限制,建議使用Runnable接口

售票系統(tǒng)

SellTicket01類繼承Thread實現(xiàn)

class SellTicket01 extends Thread{
    private static int ticketNum=100; //讓多個線程共享num
    @Override
    public void run() {
        while(true) {
                if (ticketNum <= 0) {
                    System.out.println("售票結(jié)束");
                    break;
                }
                //休眠50毫秒
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("窗口" + Thread.currentThread().getName() + "售出一張票" + "剩余票數(shù)=" + --ticketNum);
        }
    }
}
//====================main方法===========================
    public static void main(String[] args) {
        //測試
        SellTicket01 sellTicket01 = new SellTicket01();
        SellTicket01 sellTicket02 = new SellTicket01();
        SellTicket01 sellTicket03 = new SellTicket01();
        //這里會出現(xiàn)票數(shù)超賣現(xiàn)象
        sellTicket01.start();
        sellTicket02.start();
        sellTicket03.start();
}

SellTicket02類實現(xiàn)Runnable接口

class SellTicket02 implements Runnable{
    private  int ticketNum=99;
    @Override
    public void run() {
        while(true) {
            if (ticketNum <= 0) {
                System.out.println("售票結(jié)束");
                break;
            }
            //休眠50毫秒
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("窗口" + Thread.currentThread().getName() + "售出一張票" + "剩余票數(shù)=" + --ticketNum);
        }
    }
}
//=================main================
public static void main(String[] args) {
        SellTicket02 sellTicket02 = new SellTicket02();
        new Thread(sellTicket02).start();//第一個線程-窗口
        new Thread(sellTicket02).start();//第二個線程-窗口
        new Thread(sellTicket02).start();//第三個線程-窗口
    }

兩個方法都會有超票的現(xiàn)象,線程安全的問題

線程終止

基本說明

1、當(dāng)線程完成任務(wù)后,會自動退出

2、還可以通過使用變量來控制run方法退出的方式停止線程,即通知方式

通知方式

public class ThreadExit_ {
    public static void main(String[] args) throws InterruptedException {
        T t = new T();
        t.start();
        //如果希望主線程去控制t中線程的終止,需要能夠控制loop
        //修改loop,讓t退出run方法,從而終止t線程-->通知方式
        //讓主線程休眠10秒,在通知t線程退出
        Thread.sleep(10000);
        t.setLoop(false);//將T線程中的循環(huán)判斷為false
    }
}
class T extends Thread{
    private int count=0;
    private boolean loop=true;
    @Override
    public void run() {
        while (loop){
            try {
                Thread.sleep(1000);  //休眠50毫秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("T線程執(zhí)行"+ ++count);
        }
    }
    public void setLoop(boolean loop) {
        this.loop = loop;
    }
}

線程常用方法

常用第一組

1、setName:設(shè)置線程名稱,使之與參數(shù)name相同

2、getName:返回該線程的名稱

3、start:該線程開始執(zhí)行;java虛擬機底層調(diào)用該線程的start()方法

4、run:調(diào)用線程對象run方法

5、setPriority:更改線程的優(yōu)先級

6、getPriority:獲取線程的優(yōu)先級

7、sleep:在指定的毫秒數(shù)內(nèi)讓當(dāng)前正在執(zhí)行的線程休眠(暫停執(zhí)行)

8、interrupt:中斷線程

注意事項和細節(jié)

1、start底層會創(chuàng)建新的線程,調(diào)用run,run就是一個簡單的方法調(diào)用,不會啟動新線程

2、線程優(yōu)先級的范圍

3、interrupt,中斷線程,但沒有真正的結(jié)束線程,所以一般用于中斷正在休眠線程

4、sleep:線程的靜態(tài)方法,使當(dāng)前線程休眠

常用方法第二組

1、yield:線程的禮讓。讓出cpu,讓其他線程執(zhí)行,但禮讓的時間不確定,所以也不一定禮讓成功

2、join:線程的插隊。插隊的線程一旦插隊成功,則肯定先執(zhí)行完插入的線程所有的任務(wù)

案例

創(chuàng)建一個子線程,每隔1s輸出hello,輸出20次,主線程每隔1s,輸出hi,輸出20次。要求:兩個線程同時執(zhí)行,當(dāng)主線程輸出5次后,就讓子線程運行完畢,主線程再繼續(xù)

public class ThreadMethod02 {
    public static void main(String[] args) throws InterruptedException {
        T2 t2 = new T2();
        t2.start();
        for (int i = 1;i<=20;i++){
            Thread.sleep(1000);
            System.out.println("主線程(小弟)吃了"+i+"個包子");
            if (i==5){
                System.out.println("主線程(小弟)讓子線程(老大)先吃");
                //yield 禮讓
                t2.yield();
                //線程插隊,join
//                t2.join();
                System.out.println("子線程(老大)吃完,主線程(小弟)再吃");
            }
        }
    }
}
class T2 extends Thread{
    @Override
    public void run() {
        for (int i=1;i<=20;i++){
            try {
                Thread.sleep(1000);//休眠1秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("子線程(老大)吃了"+i+"個包子");
        }
    }
}

插隊的話是百分百成功的,但是禮讓如果資源過剩的話,禮讓會不成功,例如上面資源不是特別缺乏,所以禮讓會不成功

常用方法第三組

用戶線程和守護線程

1、用戶線程:也叫工作線程,當(dāng)線程的任務(wù)執(zhí)行完或通知方式結(jié)束

2、守護線程:一般是為工作線程服務(wù)的,當(dāng)所有的用戶線程結(jié)束,守護線程自動結(jié)束

3、常見的守護線程:垃圾回收機制

自定義守護線程

public class ThreadMethod03 {
    public static void main(String[] args) throws InterruptedException {
        MyDaemonThread myDaemonThread = new MyDaemonThread();
        //如果我們希望當(dāng)main線程結(jié)束后,子線程自動結(jié)束
        //只需將子線程設(shè)為守護線程即可
        myDaemonThread.setDaemon(true);
        myDaemonThread.start();
        for (int i =1;i<=10;i++){
            System.out.println("媽媽做飯");
            Thread.sleep(1000);
        }
    }
} 
class MyDaemonThread extends Thread{
    @Override
    public void run() {
        for (;;){  //等價于無限循環(huán)
            try {
                Thread.sleep(50); //休眠50毫秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("我吃飯。。。");
        }
    }
}

MyDaemonThread類的進程會在主線程進程結(jié)束后相繼結(jié)束

線程的生命周期

線程狀態(tài):線程可以處于一下狀態(tài)之一:

NEW

尚未啟動的線程處于此狀態(tài)

RUNNABLE

在Java虛擬機中執(zhí)行的線程處于此狀態(tài)

BLOCKED

被阻塞等待監(jiān)視器鎖定的線程處于此狀態(tài)

WAITING

正在等待另一個線程執(zhí)行特定動作的線程處于此狀態(tài)

TIMED_WAITING

正在等待另一個線程執(zhí)行動作達到指定等待時間的線程處于此狀態(tài)

TERMINATED

已退出的線程處于此狀態(tài)

RUNNABLE又可分為兩個狀態(tài):Ready狀態(tài):就緒狀態(tài) 和 Running運行狀態(tài)

線程同步機制

1、在多線程編程,一些敏感數(shù)據(jù)不允許被多個線程同時訪問,此時就是用同步訪問技術(shù),保證數(shù)據(jù)在任何時刻,最多有一個線程訪問,以保證數(shù)據(jù)的完整性。

2、也可以這樣理解:線程同步,即當(dāng)有一個線程在對內(nèi)存進行操作時,其他線程都不可以對這個內(nèi)存地址進行操作,直到線程完成操作,其他線程才能對該內(nèi)存地址進行操作。

利用同步解決買票超賣問題

public class SellTicket {
    public static void main(String[] args) {
        //測試同步解決超賣現(xiàn)象
        SellTicket03 sellTicket03 = new SellTicket03();
        new Thread(sellTicket03).start();//第一個線程-窗口
        new Thread(sellTicket03).start();//第二個線程-窗口
        new Thread(sellTicket03).start();//第三個線程-窗口
    }
}
//實現(xiàn)接口的方式,使用synchronized實現(xiàn)線程同步
class SellTicket03 implements Runnable{
    private boolean loop=true;
    private  int ticketNum=99;
    public synchronized void   sell(){
        if (ticketNum <= 0) {
            System.out.println("售票結(jié)束");
            loop=false;
            return;
        }
        //休眠50毫秒
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("窗口" + Thread.currentThread().getName() + "售出一張票" + "剩余票數(shù)=" + --ticketNum);
    }
    @Override
    public  void run() { //在同一時刻只能有一個線程來執(zhí)行sell方法
        while(loop) {
            sell(); //sell方法是一個同步方法
        }
    }
}

synchronized關(guān)鍵字為鎖的意思,如果有線程去調(diào)用了synchronized關(guān)鍵字修飾的方法,則不會去再有線程調(diào)用

synchronized的使用方法

  • 修飾一個代碼塊,被修飾的代碼塊稱為同步代碼塊,作用范圍是大括號{}括起來的代碼;
  • 修飾一個方法,被修飾的方法稱為同步方法,其作用范圍是整個方法;
  • 修改一個靜態(tài)方法,作用范圍是整個靜態(tài)方法;
  • 修改一個類,作用范圍是synchronized后面括號括起來的部分。

互斥鎖

基本介紹

1、Java語言中,引入了對象互斥鎖的概念,來保證共享數(shù)據(jù)操作的完整性。

2、每個對象都對應(yīng)一個可稱為互斥鎖的標(biāo)記,這個標(biāo)記用來保證在任一時刻,只能有一個線程訪問該對象

3、關(guān)鍵字synchronized來與對象的互斥鎖聯(lián)系。當(dāng)某個對象用synchronized修飾時,表明該對象在任一時刻只能由一個線程訪問

4、同步的局限性:導(dǎo)致程序的執(zhí)行效率要降低

5、同步方法(非靜態(tài)的)的鎖可以是this,也可以是其他對象(要求是同一對象)

6、同步方法(靜態(tài)的)的鎖為當(dāng)前類本身

同步方法靜態(tài)與非靜態(tài)實例

//實現(xiàn)接口的方式,使用synchronized實現(xiàn)線程同步
class SellTicket03 implements Runnable{
    private boolean loop=true;
    private  int ticketNum=99;
    Object object=new Object();
    //同步方法(靜態(tài)的)的鎖為當(dāng)前類本身
    //1.public synchronized static void m1(){} 鎖是加在SellTicket03.class  類本身
    //2.如果要在靜態(tài)方法中,實現(xiàn)一個同步代碼塊
    //3.synchronized中的參數(shù)不能為this,要為類的class 類如:
    /*public static void m2() {
        synchronized (SellTicket03.class) {
            System.out.println("m2");
        }
    }*/
    public synchronized static void m1(){
    }
    public static void m2() {
        synchronized (SellTicket03.class) {
            System.out.println("m2");
        }
    }

    //1、 public synchronized void   sell(){}這是一個同步方法
    //2、這時鎖在this對象
    //3、也可以在代碼塊上寫synchronize  , 同步代碼塊
    public /*synchronized*/ void   sell() {
        synchronized (object) {
            if (ticketNum <= 0) {
                System.out.println("售票結(jié)束");
                loop = false;
                return;
            }
            //休眠50毫秒
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("窗口" + Thread.currentThread().getName() + "售出一張票" + "剩余票數(shù)=" + --ticketNum);
        }
    }
    @Override
    public  void run() { //在同一時刻只能有一個線程來執(zhí)行sell方法
        while(loop) {
            sell(); //sell方法是一個同步方法
        }
    }
}

注意事項和細節(jié)

1、同步方法如果沒有使用static修飾:默認鎖對象為this

2、如果方法使用static修飾,默認鎖對象:當(dāng)前類.class

3、實現(xiàn)的落地步驟

  • 需要先分析上鎖的代碼
  • 選擇同步代碼塊或同步方法
  • 要求多個線程的鎖對象為同一個即可!

線程死鎖

public class DeadLock_ {
    public static void main(String[] args) {
        //模擬一個死鎖現(xiàn)象
    DeadLockDemo A=new DeadLockDemo(true);
    DeadLockDemo B=new DeadLockDemo(false);
    deadLockDemo1.start();
    deadLockDemo2.start();
    }
}
class DeadLockDemo extends Thread{
    static Object o1 = new Object();  //保證多線程,共享一個對象,這里使用static
    static Object o2 = new Object();
    boolean flag;
    public DeadLockDemo(boolean flag){  //構(gòu)造器
        this.flag = flag;
    }

    @Override
    public void run() {
        //下面的業(yè)務(wù)邏輯的分析
        //1.如果flag為T , 線程就會先得到/持有 o1 對象鎖 , 然后嘗試去獲得 o2對象鎖
        //2.如果線程A 得不到o2對象鎖,就會Blocked
        //3.如果flag為F,線程B就會先得到/持有 o2 對象鎖,然后嘗試去獲取 o1 對象鎖
        //4.如果線程B 得不到 o1 對象鎖,就會Blocked
        if (flag){
            synchronized (o1){   //對象互斥鎖,下面就是我們同步代碼
                System.out.println(Thread.currentThread().getName() + "進入1");
                synchronized (o2){  //這里獲得li對象的監(jiān)視權(quán)
                    System.out.println(Thread.currentThread().getName()+"進入2");
                }
            }
        }else {
            synchronized (o2){
                System.out.println(Thread.currentThread().getName()+"進入3");
                synchronized (o1){
                    System.out.println(Thread.currentThread().getName()+"進入4");
                }
            }
        }
    }
}

因為線程A會去搶線程B占著的對象,線程B也會去搶線程A占著的對象,所以會出現(xiàn)線程鎖死的現(xiàn)象,寫代碼的時候要避免這個錯誤

釋放鎖

下面操作會釋放鎖

1、當(dāng)前線程的同步方法、同步代碼塊執(zhí)行結(jié)束

案例:上廁所,完事出來

2、當(dāng)前線程在同步代碼塊、同步方法中遇到break、return

案例:沒有正常的完事,經(jīng)理叫你去修改bug,不得已出來

3、當(dāng)前線程在同步代碼塊、同步方法中出現(xiàn)了未處理的Error或Exception,導(dǎo)致異常結(jié)束

案例:沒有正常的完事,發(fā)現(xiàn)忘記帶紙,不得已出來

4、當(dāng)前線程在同步代碼塊、同步方法中執(zhí)行了線程對象的wait()方法,當(dāng)前線程暫停,并釋放鎖。

案例:沒有正常完事,覺得需要醞釀下,所以出來等會在進去

下面操作不會釋放鎖

1、線程執(zhí)行同步代碼塊或同步方法時,程序調(diào)用了Thread.sleep()、Thread.yield()方法暫停當(dāng)前線程的執(zhí)行,不會釋放鎖

案例:上廁所,太困了,在坑位上瞇了一會

2、線程執(zhí)行同步代碼塊時,其他線程調(diào)用了該線程的suspend()方法將該線程掛起,該線程不會釋放鎖

提示:應(yīng)盡量避免使用suspend()和resume()來控制線程,方法不再推薦使用

練習(xí)題

一、

(1)在main方法中啟動兩個線程

(2)第一個線程循環(huán)隨機打印100以內(nèi)的整數(shù)

(3)直到第二個線程從鍵盤上讀取了"Q"命令

通過線程守護解決

public class homeWork01 {
    public static void main(String[] args) {
        //創(chuàng)建線程B,并運行
        B b=new B();
        b.start();
    }
}
class A extends Thread{
    @Override
    public void run() {
        while (true){
            try {
                //休眠1秒運行
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //打印隨機數(shù)
            int num = (int)(Math.random()*100);
            System.out.println(num);
        }
    }
}
class B extends Thread{
    @Override
    public void run() {
        //創(chuàng)建A線程對象,并創(chuàng)建守護線程
        A a=new A();
        a.setDaemon(true);
        a.start();
        while (true) {
            //當(dāng)輸入Q的時候B線程結(jié)束,因為是守護線程,所以線程A也會跟著結(jié)束
            System.out.println("請輸入你的指令");
            Scanner sc = new Scanner(System.in);
            String Z = sc.next();
            System.out.println(Z);
            if (Z.equals("Q")) {
                System.out.println("B線程結(jié)束");
                break;
            }
        }
    }
}

通過通知方式解決

public class homeWork01 {
    public static void main(String[] args) {
        //創(chuàng)建線程A、B,并且執(zhí)行線程A、B
        A a= new A();
        B b=new B(a);
        a.start();
        b.start();
    }
}
class A extends Thread{
     private boolean loop=true;
    //創(chuàng)建setLoop用來通知
    public void setLoop(boolean loop) {
        this.loop = loop;
    }
    @Override
    public void run() {
        while (loop){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            int num = (int)(Math.random()*100);
            System.out.println(num);
        }
    }
}
class B extends Thread{
    A a;
    //通過B的構(gòu)造器,傳入main中的線程A
    public B(A a){
        this.a=a;
    }
    @Override
    public void run() {
        while (true) {
            System.out.println("請輸入你的指令");
            Scanner sc = new Scanner(System.in);
            String Z = sc.next();
            System.out.println(Z);
            if (Z.equals("Q")) {
                //通過setLoop提醒線程A結(jié)束
                a.setLoop(false);
                break;
            }
        }
    }
}

二、

(1)有兩個用戶分別從同一個卡上取錢(總額:10000)

(2)每次都取1000,當(dāng)余額不足時,就不能取款了

(3)不能出現(xiàn)超取現(xiàn)象 —>線程同步問題

同步方法

public class homeWork02 {
    public static void main(String[] args) {
        C c=new C();
        //將兩個線程運行
        new Thread(c).start();
        new Thread(c).start();
    }
}
class C implements Runnable{
   private static boolean loop=true;
   private static int money=10000;
    @Override
    public void run() {
        while (loop){
            //讓兩個線程去搶同步方法
            quMoney();
        }
    }
    public synchronized void quMoney(){
        if (money<=0){
            System.out.println("余額不足,線程退出"+Thread.currentThread().getName());
            loop=false;
            return;
        }
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        money=money-1000;
        System.out.println(Thread.currentThread().getName()+"從余額中取到了1000元還剩"+money+"元");
    }
}

通過創(chuàng)建同步方法,避免超取現(xiàn)象

同步代碼塊

public class homeWork03 {
    public static void main(String[] args) {
        T t=new T();
        Thread thread=new Thread(t);
        Thread thread1=new Thread(t);
        thread.setName("t1");
        thread1.setName("t2");
        thread.start();
        thread1.start();
    }
}
//編寫取款的線程
//因為這里涉及到多個程序共享資源,所以我們使用實現(xiàn)Runnable方式
class T implements Runnable{
    private int money=10000;
    @Override
    public void run() {
        while (true){
            //解讀
            //1.這里使用 synchronized 實現(xiàn)了線程同步
            //2.當(dāng)多個線程執(zhí)行到這里時,就會去爭奪 this 對象鎖
            //3.那個線程獲取到了this鎖,就執(zhí)行 synchronized 代碼塊,執(zhí)行完后,會釋放this對象鎖
            //4.獲取不到this對象鎖,就會blocked(阻塞),準(zhǔn)備繼續(xù)爭奪
            synchronized (this) {
                if (money < 1000) {
                    System.out.println("余額不足");
                    break;
                }
                money -= 1000;
                System.out.println(Thread.currentThread().getName() + "取出了1000 當(dāng)前余額" + money);
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

ss T implements Runnable{
private int money=10000;

@Override
public void run() {
    while (true){
        //解讀
        //1.這里使用 synchronized 實現(xiàn)了線程同步
        //2.當(dāng)多個線程執(zhí)行到這里時,就會去爭奪 this 對象鎖
        //3.那個線程獲取到了this鎖,就執(zhí)行 synchronized 代碼塊,執(zhí)行完后,會釋放this對象鎖
        //4.獲取不到this對象鎖,就會blocked(阻塞),準(zhǔn)備繼續(xù)爭奪
        synchronized (this) {
            if (money < 1000) {
                System.out.println("余額不足");
                break;
            }
            money -= 1000;
            System.out.println(Thread.currentThread().getName() + "取出了1000 當(dāng)前余額" + money);
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

總結(jié)

本篇文章就到這里了,希望能給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

  • java實現(xiàn)json字符串格式化處理的工具類

    java實現(xiàn)json字符串格式化處理的工具類

    這篇文章主要為大家詳細介紹了如何使用java實現(xiàn)json字符串格式化處理的工具類,文中的示例代碼簡潔易懂,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-01-01
  • @Scheduled在springboot中的使用方式

    @Scheduled在springboot中的使用方式

    這篇文章主要介紹了@Scheduled在springboot中的使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • Spring中屬性注入詳解

    Spring中屬性注入詳解

    這篇文章主要為大家詳細介紹了Spring中屬性注入,演示了int、String、數(shù)組、list等屬性的注入,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-10-10
  • IDEA創(chuàng)建自定義模板圖文教程

    IDEA創(chuàng)建自定義模板圖文教程

    我們每次在使用IntelliJ IDEA 時總會有一些文件是一直被創(chuàng)建的,今天我們就來學(xué)習(xí)一下IntelliJ IDEA 的自定義模板功能,文中有詳細的圖文介紹,需要的朋友可以參考下
    2021-05-05
  • java.lang.Runtime.exec的左膀右臂:流輸入和流讀取詳解

    java.lang.Runtime.exec的左膀右臂:流輸入和流讀取詳解

    這篇文章主要介紹了java.lang.Runtime.exec的左膀右臂:流輸入和流讀取詳解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • DragChartPanel可拖拽曲線應(yīng)用詳解

    DragChartPanel可拖拽曲線應(yīng)用詳解

    這篇文章主要為大家詳細介紹了DragChartPanel可拖拽曲線的應(yīng)用,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • Java啟動Tomcat的實現(xiàn)步驟

    Java啟動Tomcat的實現(xiàn)步驟

    本文主要介紹了Java啟動Tomcat的實現(xiàn)步驟,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-05-05
  • Java簡單冒泡排序示例解析

    Java簡單冒泡排序示例解析

    這篇文章主要介紹了Java簡單冒泡排序示例解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • java?ResourceBundle讀取properties文件方式

    java?ResourceBundle讀取properties文件方式

    這篇文章主要介紹了java?ResourceBundle讀取properties文件方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • Java死鎖的產(chǎn)生原因及解決方法總結(jié)

    Java死鎖的產(chǎn)生原因及解決方法總結(jié)

    Java中的死鎖是指多個線程同時占用一些共享資源且彼此相互等待,從而導(dǎo)致所有的線程都被阻塞,不能繼續(xù)執(zhí)行程序的情況,本文小編給大家介紹了Java死鎖的產(chǎn)生原因及解決方法總結(jié),需要的朋友可以參考下
    2023-11-11

最新評論