日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

Java基础day20

發(fā)布時(shí)間:2025/3/12 java 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java基础day20 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Java基礎(chǔ)day20

  • Java基礎(chǔ)day20-多線程
  • 1.實(shí)現(xiàn)多線程
    • 1.1進(jìn)程和線程
    • 1.2實(shí)現(xiàn)多線程方式一:繼承Thread類(lèi)
    • 1.3設(shè)置和獲取線程名稱(chēng)
    • 1.4線程優(yōu)先級(jí)
    • 1.5線程控制
    • 1.6線程的生命周期
    • 1.7實(shí)現(xiàn)多線程方式二:實(shí)現(xiàn)Runnable接口
  • 2.線程同步
    • 2.1賣(mài)票
    • 2.2賣(mài)票案例的問(wèn)題
    • 2.3同步代碼塊解決數(shù)據(jù)安全問(wèn)題
    • 2.4同步方法解決數(shù)據(jù)安全問(wèn)題
    • 2.5線程安全的類(lèi)
    • 2.6Lock鎖
  • 3.生產(chǎn)者消費(fèi)者
    • 3.1生產(chǎn)者和消費(fèi)者模式概述
    • 3.2生產(chǎn)者和消費(fèi)者案例

Java基礎(chǔ)day20-多線程

1.實(shí)現(xiàn)多線程

1.1進(jìn)程和線程

  • 進(jìn)程:是正在運(yùn)行的程序
    是系統(tǒng)進(jìn)行資源分配和調(diào)用的獨(dú)立單位
    每一個(gè)進(jìn)程都有它自己的內(nèi)存空間和系統(tǒng)資源
  • 線程:是進(jìn)程中的單個(gè)順序控制流,是一條執(zhí)行路徑
    單線程:一個(gè)進(jìn)程如果只有一條執(zhí)行路徑,則稱(chēng)為單線程程序
    多線程:一個(gè)進(jìn)程如果有多條執(zhí)行路徑,則稱(chēng)為多線程程序

1.2實(shí)現(xiàn)多線程方式一:繼承Thread類(lèi)

  • 方法介紹
方法名說(shuō)明
void run()在線程開(kāi)啟后,此方法將被調(diào)用執(zhí)行
void start()使此線程開(kāi)始執(zhí)行,Java虛擬機(jī)會(huì)調(diào)用run方法()
  • 實(shí)現(xiàn)步驟
    定義一個(gè)類(lèi)MyThread繼承Thread類(lèi) 在MyThread類(lèi)中重寫(xiě)run()方法
    創(chuàng)建MyThread類(lèi)的對(duì)象
    啟動(dòng)線程

  • 代碼演示

//線程定義 public class myThread extends Thread{@Overridepublic void run() {for (int i=0;i<100;i++){System.out.println(i);}} } //測(cè)試類(lèi) public class test1 {public static void main(String[] args) {myThread m1 = new myThread();myThread m2 = new myThread();// m1.run(); // m2.run();//void start() 導(dǎo)致此線程開(kāi)始執(zhí)行; Java虛擬機(jī)調(diào)用此線程的run方法m1.start();m2.start();} }
  • 兩個(gè)小問(wèn)題
    為什么要重寫(xiě)run()方法?
    ? 因?yàn)閞un()是用來(lái)封裝被線程執(zhí)行的代碼
    run()方法和start()方法的區(qū)別?
    ?run():封裝線程執(zhí)行的代碼,直接調(diào)用,相當(dāng)于普通方法的調(diào)用
    ?start():啟動(dòng)線程;然后由JVM調(diào)用此線程的run()方法

1.3設(shè)置和獲取線程名稱(chēng)

  • 方法介紹
方法名說(shuō)明
void setName(String name)將此線程的名稱(chēng)更改為等于參數(shù)name
String getName()返回此線程的名稱(chēng)
Thread currentThread()返回對(duì)當(dāng)前正在執(zhí)行的線程對(duì)象的引用
  • 代碼演示
public class test2 {public static void main(String[] args) {myThread my1 = new myThread();myThread my2 = new myThread();//void setName(String name):將此線程的名稱(chēng)更改為等于參數(shù) namemy1.setName("高鐵");my2.setName("飛機(jī)");//Thread(String name) // myThread my1 = new myThread("高鐵"); // myThread my2 = new myThread("飛機(jī)");my1.start();my2.start();//static Thread currentThread() 返回對(duì)當(dāng)前正在執(zhí)行的線程對(duì)象的引用System.out.println(Thread.currentThread().getName());} }

1.4線程優(yōu)先級(jí)

  • 線程調(diào)度
    兩種調(diào)度方式
    ? 分時(shí)調(diào)度模型:所有線程輪流使用 CPU 的使用權(quán),平均分配每個(gè)線程占用 CPU 的時(shí)間片
    ? 搶占式調(diào)度模型:優(yōu)先讓優(yōu)先級(jí)高的線程使用 CPU,如果線程的優(yōu)先級(jí)相同,那么會(huì)隨機(jī)選擇一個(gè),優(yōu)先級(jí)高的線程獲取的 CPU 時(shí)間片相對(duì)多一些
    Java使用的是搶占式調(diào)度模型
    隨機(jī)性
    假如計(jì)算機(jī)只有一個(gè) CPU,那么 CPU 在某一個(gè)時(shí)刻只能執(zhí)行一條指令,線程只有得到CPU時(shí)間片,也就是使用權(quán),才可以執(zhí)行指令。所以說(shuō)多線程程序的執(zhí)行是有隨機(jī)性,因?yàn)檎l(shuí)搶到CPU的使用權(quán)是不一定的優(yōu)先級(jí)相關(guān)方法
方法名說(shuō)明
final int getPriority()返回此線程的優(yōu)先級(jí)
final void setPriority(int newPriority)更改此線程的優(yōu)先級(jí) 線程默認(rèn)優(yōu)先級(jí)是5;線程優(yōu)先級(jí)的范圍是:1-10
public class ThreadPriority extends Thread{@Overridepublic void run() {for (int i = 0;i<100;i++){System.out.println(getName()+":"+i);}} }public class test3 {public static void main(String[] args) {ThreadPriority tp1 = new ThreadPriority();ThreadPriority tp2 = new ThreadPriority();ThreadPriority tp3 = new ThreadPriority();tp1.setName("高鐵");tp2.setName("飛機(jī)");tp3.setName("汽車(chē)");//public final int getPriority():返回此線程的優(yōu)先級(jí)System.out.println(tp1.getPriority());// 5System.out.println(tp2.getPriority());// 5System.out.println(tp3.getPriority()); //5//public final void setPriority(int newPriority):更改此線程的優(yōu)先級(jí)// tp1.setPriority(10000); //IllegalArgumentExceptionSystem.out.println(Thread.MAX_PRIORITY); //10System.out.println(Thread.MIN_PRIORITY); //1System.out.println(Thread.NORM_PRIORITY); //5//設(shè)置正確的優(yōu)先級(jí)tp1.setPriority(5);tp2.setPriority(10);tp3.setPriority(1);tp1.start();tp2.start();tp3.start();} }

1.5線程控制

  • 相關(guān)方法
方法名說(shuō)明
static void sleep(long millis)使當(dāng)前正在執(zhí)行的線程停留(暫停執(zhí)行)指定的毫秒數(shù)
void join()等待這個(gè)線程死亡
void setDaemon(boolean on)將此線程標(biāo)記為守護(hù)線程,當(dāng)運(yùn)行的線程都是守護(hù)線程時(shí),Java虛擬機(jī)將退出
  • 代碼演示
//sleep演示 public class ThreadSleep extends Thread {@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(getName() + ":" + i);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}} } //測(cè)試類(lèi) public class test4 {public static void main(String[] args) {ThreadSleep ts1 = new ThreadSleep();ThreadSleep ts2 = new ThreadSleep();ThreadSleep ts3 = new ThreadSleep();ts1.setName("曹操");ts2.setName("劉備");ts3.setName("孫權(quán)");ts1.start();ts2.start();ts3.start();} } //Join演示: public class ThreadJoin extends Thread{@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(getName() + ":" + i);}} } public class test5 {public static void main(String[] args) {ThreadJoin tj1 = new ThreadJoin();ThreadJoin tj2 = new ThreadJoin();ThreadJoin tj3 = new ThreadJoin();tj1.setName("康熙");tj2.setName("四阿哥");tj3.setName("六阿哥");tj1.start();try {tj1.join();} catch (InterruptedException e) {e.printStackTrace();}tj2.start();tj3.start();} }//Daemon演示: public class ThreadDaemon extends Thread{@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(getName() + ":" + i);}} } public class test6 {public static void main(String[] args) {ThreadDaemon td1 = new ThreadDaemon();ThreadDaemon td2 = new ThreadDaemon();td1.setName("張飛");td2.setName("關(guān)羽");//設(shè)置主線程為劉備Thread.currentThread().setName("劉備");//設(shè)置守護(hù)線程td1.setDaemon(true);td2.setDaemon(true);td1.start();td2.start();for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() + ":" + i);}} }

1.6線程的生命周期

線程一共有五種狀態(tài),線程在各種狀態(tài)之間轉(zhuǎn)換。

1.7實(shí)現(xiàn)多線程方式二:實(shí)現(xiàn)Runnable接口

Thread構(gòu)造方法

方法名說(shuō)明
Thread(Runnable target)分配一個(gè)新的Thread對(duì)象
Thread(Runnable target, String name)分配一個(gè)新的Thread對(duì)象
  • 實(shí)現(xiàn)步驟
    定義一個(gè)類(lèi)MyRunnable實(shí)現(xiàn)Runnable接口
    在MyRunnable類(lèi)中重寫(xiě)run()方法
    創(chuàng)建MyRunnable類(lèi)的對(duì)象
    創(chuàng)建Thread類(lèi)的對(duì)象,把MyRunnable對(duì)象作為構(gòu)造方法的參數(shù)
    啟動(dòng)線程
  • 代碼演示
public class MyRunnable implements Runnable {@Overridepublic void run() {for (int i = 0; i < 100; i++){System.out.println(Thread.currentThread().getName()+":"+i);}} } public class test7 {public static void main(String[] args) {//創(chuàng)建MyRunnable類(lèi)的對(duì)象MyRunnable my = new MyRunnable();//創(chuàng)建Thread類(lèi)的對(duì)象,把MyRunnable對(duì)象作為構(gòu)造方法的參數(shù)// Thread(Runnable target) // Thread t1 = new Thread(my); // Thread t2 = new Thread(my);//Thread(Runnable target, String name)Thread t1 = new Thread(my,"高鐵");Thread t2 = new Thread(my,"飛機(jī)");//啟動(dòng)線程t1.start();t2.start();} }
  • 多線程的實(shí)現(xiàn)方案有兩種
    繼承Thread類(lèi)
    實(shí)現(xiàn)Runnable接口
  • 相比繼承Thread類(lèi),實(shí)現(xiàn)Runnable接口的好處
    避免了Java單繼承的局限性
    適合多個(gè)相同程序的代碼去處理同一個(gè)資源的情況,把線程和程序的代碼、數(shù)據(jù)有效分離,較好的體現(xiàn)
    了面向?qū)ο蟮脑O(shè)計(jì)思想

2.線程同步

2.1賣(mài)票

  • 案例需求
    某電影院目前正在上映國(guó)產(chǎn)大片,共有100張票,而它有3個(gè)窗口賣(mài)票,請(qǐng)?jiān)O(shè)計(jì)一個(gè)程序模擬該電影院賣(mài)票
  • 實(shí)現(xiàn)步驟
    • 定義一個(gè)類(lèi)SellTicket實(shí)現(xiàn)Runnable接口,里面定義一個(gè)成員變量:private int tickets = 100;
    • 在SellTicket類(lèi)中重寫(xiě)run()方法實(shí)現(xiàn)賣(mài)票,代碼步驟如下
    • 判斷票數(shù)大于0,就賣(mài)票,并告知是哪個(gè)窗口賣(mài)的
    • 賣(mài)了票之后,總票數(shù)要減1
    • 票沒(méi)有了,也可能有人來(lái)問(wèn),所以這里用死循環(huán)讓賣(mài)票的動(dòng)作一直執(zhí)行
    • 定義一個(gè)測(cè)試類(lèi)SellTicketDemo,里面有main方法,代碼步驟如下
    • 創(chuàng)建SellTicket類(lèi)的對(duì)象
    • 創(chuàng)建三個(gè)Thread類(lèi)的對(duì)象,把SellTicket對(duì)象作為構(gòu)造方法的參數(shù),并給出對(duì)應(yīng)的窗口名稱(chēng)
    • 啟動(dòng)線程
  • 代碼實(shí)現(xiàn)
public class SellTicket implements Runnable {private int tickets = 100;@Overridepublic void run() {while (true){if (tickets>0){System.out.println(Thread.currentThread().getName()+"正在出售第"+tickets+"張票");tickets--;}}} }public class test1 {public static void main(String[] args) {//創(chuàng)建SellTicket類(lèi)的對(duì)象SellTicket st = new SellTicket();//創(chuàng)建三個(gè)Thread類(lèi)的對(duì)象,把SellTicket對(duì)象作為構(gòu)造方法的參數(shù),并給出對(duì)應(yīng)的窗口名稱(chēng)Thread t1 = new Thread(st,"窗口1");Thread t2 = new Thread(st,"窗口2");Thread t3 = new Thread(st,"窗口3");//啟動(dòng)線程t1.start();t2.start();t3.start();} }

2.2賣(mài)票案例的問(wèn)題

  • 賣(mài)票出現(xiàn)了問(wèn)題
    相同的票出現(xiàn)了多次
    出現(xiàn)了負(fù)數(shù)的票
  • 問(wèn)題產(chǎn)生原因
    線程執(zhí)行的隨機(jī)性導(dǎo)致的
//解決票數(shù)為復(fù)數(shù)的問(wèn)題,但是仍會(huì)出現(xiàn)重復(fù) public class SellTicket implements Runnable {private int tickets = 100;@Overridepublic void run() {while (true){if (tickets>0){try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"正在出售第"+tickets+"張票");tickets--;}}} }

2.3同步代碼塊解決數(shù)據(jù)安全問(wèn)題

  • 安全問(wèn)題出現(xiàn)的條件
    是多線程環(huán)境
    有共享數(shù)據(jù)
    有多條語(yǔ)句操作共享數(shù)據(jù)
  • 如何解決多線程安全問(wèn)題呢?
    基本思想:讓程序沒(méi)有安全問(wèn)題的環(huán)境
  • 怎么實(shí)現(xiàn)呢?
    把多條語(yǔ)句操作共享數(shù)據(jù)的代碼給鎖起來(lái),讓任意時(shí)刻只能有一個(gè)線程執(zhí)行即可
    Java提供了同步代碼塊的方式來(lái)解決
  • 同步代碼塊格式:
synchronized(任意對(duì)象) { 多條語(yǔ)句操作共享數(shù)據(jù)的代碼 }

synchronized(任意對(duì)象):就相當(dāng)于給代碼加鎖了,任意對(duì)象就可以看成是一把鎖

  • 同步的好處和弊端
    好處:解決了多線程的數(shù)據(jù)安全問(wèn)題
    弊端:當(dāng)線程很多時(shí),因?yàn)槊總€(gè)線程都會(huì)去判斷同步上的鎖,這是很耗費(fèi)資源的,無(wú)形中會(huì)降低程序的運(yùn)行效率
  • 代碼演示
public class SellTicket implements Runnable {private int tickets = 100;private Object obj = new Object();@Overridepublic void run() {while (true) {//tickets = 100;// t1,t2,t3// 假設(shè)t1搶到了CPU的執(zhí)行權(quán)// 假設(shè)t2搶到了CPU的執(zhí)行權(quán)synchronized (obj) {//t1進(jìn)來(lái)后,就會(huì)把這段代碼給鎖起來(lái)if (tickets > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "張票");tickets--;}}}} }public class test1 {public static void main(String[] args) {//創(chuàng)建SellTicket類(lèi)的對(duì)象SellTicket st = new SellTicket();//創(chuàng)建三個(gè)Thread類(lèi)的對(duì)象,把SellTicket對(duì)象作為構(gòu)造方法的參數(shù),并給出對(duì)應(yīng)的窗口名稱(chēng)Thread t1 = new Thread(st,"窗口1");Thread t2 = new Thread(st,"窗口2");Thread t3 = new Thread(st,"窗口3");//啟動(dòng)線程t1.start();t2.start();t3.start();} }

2.4同步方法解決數(shù)據(jù)安全問(wèn)題

  • 同步方法的格式
    同步方法:就是把synchronized關(guān)鍵字加到方法上
修飾符 synchronized 返回值類(lèi)型 方法名(方法參數(shù)) { 方法體; }

同步方法的鎖對(duì)象是什么呢?
this

  • 靜態(tài)同步方法
    同步靜態(tài)方法:就是把synchronized關(guān)鍵字加到靜態(tài)方法上
修飾符 static synchronized 返回值類(lèi)型 方法名(方法參數(shù)) { 方法體; }

同步靜態(tài)方法的鎖對(duì)象是什么呢?
類(lèi)名.class

  • 代碼演示
public class SellTicket implements Runnable {private static int tickets = 100;private int x = 0;@Overridepublic void run() {while (true){sellTicket();}}//同步方法 // private synchronized void sellTicket() { // if (tickets > 0){ // try { // Thread.sleep(100); // } catch (InterruptedException e) { // e.printStackTrace(); // } // System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "張票"); // tickets--; // } // }// 靜態(tài)同步方法private static synchronized void sellTicket() {if (tickets > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "張票");tickets--;}} }public class test1 {public static void main(String[] args) {//創(chuàng)建SellTicket類(lèi)的對(duì)象SellTicket st = new SellTicket();//創(chuàng)建三個(gè)Thread類(lèi)的對(duì)象,把SellTicket對(duì)象作為構(gòu)造方法的參數(shù),并給出對(duì)應(yīng)的窗口名稱(chēng)Thread t1 = new Thread(st,"窗口1");Thread t2 = new Thread(st,"窗口2");Thread t3 = new Thread(st,"窗口3");//啟動(dòng)線程t1.start();t2.start();t3.start();} }

2.5線程安全的類(lèi)

  • StringBuffer
    • 線程安全,可變的字符序列
    • 從版本JDK 5開(kāi)始,被StringBuilder 替代。 通常應(yīng)該使用StringBuilder類(lèi),因?yàn)樗С炙邢嗤牟僮?#xff0c;但它更快,因?yàn)樗粓?zhí)行同步
  • Vector
    • 從Java 2平臺(tái)v1.2開(kāi)始,該類(lèi)改進(jìn)了List接口,使其成為Java Collections Framework的成員。 與新的集
    • 合實(shí)現(xiàn)不同, Vector被同步。 如果不需要線程安全的實(shí)現(xiàn),建議使用ArrayList代替Vector
  • Hashtable
    • 該類(lèi)實(shí)現(xiàn)了一個(gè)哈希表,它將鍵映射到值。 任何非null對(duì)象都可以用作鍵或者值
    • 從Java 2平臺(tái)v1.2開(kāi)始,該類(lèi)進(jìn)行了改進(jìn),實(shí)現(xiàn)了Map接口,使其成為Java Collections Framework的成員。 與新的集合實(shí)現(xiàn)不同, Hashtable被同步。 如果不需要線程安全的實(shí)現(xiàn),建議使用HashMap代替Hashtable

2.6Lock鎖

雖然我們可以理解同步代碼塊和同步方法的鎖對(duì)象問(wèn)題,但是我們并沒(méi)有直接看到在哪里加上了鎖,在哪里釋放了鎖,為了更清晰的表達(dá)如何加鎖和釋放鎖,JDK5以后提供了一個(gè)新的鎖對(duì)象LockLock是接口不能直接實(shí)例化,這里采用它的實(shí)現(xiàn)類(lèi)ReentrantLock來(lái)實(shí)例化
  • ReentrantLock構(gòu)造方法
方法名說(shuō)明
ReentrantLock()創(chuàng)建一個(gè)ReentrantLock的實(shí)例
  • 加鎖解鎖方法
方法名說(shuō)明
void lock()獲得鎖
void unlock()釋放鎖
  • 代碼演示
//賣(mài)票方法 import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock;public class SellTicket implements Runnable{private int tickets = 100;private Lock lock = new ReentrantLock();@Overridepublic void run() {while (true){try {lock.lock();if (tickets>0){try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "張票");tickets--;}} finally {lock.unlock();}}} } //測(cè)試類(lèi) public class test1 {public static void main(String[] args) {SellTicket st = new SellTicket();Thread t1 = new Thread(st, "窗口1");Thread t2 = new Thread(st, "窗口2");Thread t3 = new Thread(st, "窗口3");t1.start();t2.start();t3.start();} }

3.生產(chǎn)者消費(fèi)者

3.1生產(chǎn)者和消費(fèi)者模式概述

  • 概述
    生產(chǎn)者消費(fèi)者模式是一個(gè)十分經(jīng)典的多線程協(xié)作的模式,弄懂生產(chǎn)者消費(fèi)者問(wèn)題能夠讓我們對(duì)多線程編程的理解更加深刻。
    所謂生產(chǎn)者消費(fèi)者問(wèn)題,實(shí)際上主要是包含了兩類(lèi)線程:
    一類(lèi)是生產(chǎn)者線程用于生產(chǎn)數(shù)據(jù)
    一類(lèi)是消費(fèi)者線程用于消費(fèi)數(shù)據(jù)
    為了解耦生產(chǎn)者和消費(fèi)者的關(guān)系,通常會(huì)采用共享的數(shù)據(jù)區(qū)域,就像是一個(gè)倉(cāng)庫(kù)
    生產(chǎn)者生產(chǎn)數(shù)據(jù)之后直接放置在共享數(shù)據(jù)區(qū)中,并不需要關(guān)心消費(fèi)者的行為
    消費(fèi)者只需要從共享數(shù)據(jù)區(qū)中去獲取數(shù)據(jù),并不需要關(guān)心生產(chǎn)者的行為
  • Object類(lèi)的等待和喚醒方法
方法名說(shuō)明
void wait()導(dǎo)致當(dāng)前線程等待,直到另一個(gè)線程調(diào)用該對(duì)象的 notify()方法或 notifyAll()方法
void notify()喚醒正在等待對(duì)象監(jiān)視器的單個(gè)線程
void notifyAll()喚醒正在等待對(duì)象監(jiān)視器的所有線程

3.2生產(chǎn)者和消費(fèi)者案例

  • 案例需求
    生產(chǎn)者消費(fèi)者案例中包含的類(lèi):
    奶箱類(lèi)(Box):定義一個(gè)成員變量,表示第x瓶奶,提供存儲(chǔ)牛奶和獲取牛奶的操作
    生產(chǎn)者類(lèi)(Producer):實(shí)現(xiàn)Runnable接口,重寫(xiě)run()方法,調(diào)用存儲(chǔ)牛奶的操作
    消費(fèi)者類(lèi)(Customer):實(shí)現(xiàn)Runnable接口,重寫(xiě)run()方法,調(diào)用獲取牛奶的操作
    測(cè)試類(lèi)(BoxDemo):里面有main方法,main方法中的代碼步驟如下
    ①創(chuàng)建奶箱對(duì)象,這是共享數(shù)據(jù)區(qū)域
    ②創(chuàng)建消費(fèi)者創(chuàng)建生產(chǎn)者對(duì)象,把奶箱對(duì)象作為構(gòu)造方法參數(shù)傳遞,因?yàn)樵谶@個(gè)類(lèi)中要調(diào)用存儲(chǔ)牛奶的操作
    ③對(duì)象,把奶箱對(duì)象作為構(gòu)造方法參數(shù)傳遞,因?yàn)樵谶@個(gè)類(lèi)中要調(diào)用獲取牛奶的操作
    ④創(chuàng)建2個(gè)線程對(duì)象,分別把生產(chǎn)者對(duì)象和消費(fèi)者對(duì)象作為構(gòu)造方法參數(shù)傳遞
    ⑤啟動(dòng)線程
  • 代碼實(shí)現(xiàn)
public class Box {//定義一個(gè)成員變量,表示第x瓶奶private int milk;//定義一個(gè)成員變量,表示奶箱的狀態(tài)private boolean state = false;//提供存儲(chǔ)牛奶和獲取牛奶的操作public synchronized void put(int milk) {//如果有牛奶,等待消費(fèi)if (state){try {wait();} catch (InterruptedException e) {e.printStackTrace();}}//如果沒(méi)有牛奶,就生產(chǎn)牛奶this.milk = milk;System.out.println("送奶工將第" + this.milk + "瓶奶放入奶箱");//生產(chǎn)完畢之后,修改奶箱狀態(tài)state = true;//喚醒其他等待的線程notifyAll();}public synchronized void get() {//如果沒(méi)有牛奶,等待生產(chǎn)if(!state) {try {wait();} catch (InterruptedException e) {e.printStackTrace();}}//如果有牛奶,就消費(fèi)牛奶System.out.println("用戶(hù)拿到第" + this.milk + "瓶奶");//消費(fèi)完畢之后,修改奶箱狀態(tài)state = false;//喚醒其他等待的線程notifyAll();} }public class Producer implements Runnable {private Box b;public Producer() {}public Producer(Box b) {this.b = b;}@Overridepublic void run() {for (int i = 1; i <= 30; i++) {b.put(i);}} }public class Customer implements Runnable{private Box b;public Customer(Box b) {this.b = b;}@Overridepublic void run() {while (true){b.get();}} }public class test {public static void main(String[] args) {//創(chuàng)建奶箱對(duì)象,這是共享數(shù)據(jù)區(qū)域Box b = new Box();//創(chuàng)建生產(chǎn)者對(duì)象,把奶箱對(duì)象作為構(gòu)造方法參數(shù)傳遞,因?yàn)樵谶@個(gè)類(lèi)中要調(diào)用存儲(chǔ)牛奶的操作Producer p = new Producer(b);// 創(chuàng)建消費(fèi)者對(duì)象,把奶箱對(duì)象作為構(gòu)造方法參數(shù)傳遞,因?yàn)樵谶@個(gè)類(lèi)中要調(diào)用獲取牛奶的操作Customer c = new Customer(b);//創(chuàng)建2個(gè)線程對(duì)象,分別把生產(chǎn)者對(duì)象和消費(fèi)者對(duì)象作為構(gòu)造方法參數(shù)傳遞Thread t1 = new Thread(p);Thread t2 = new Thread(c);//啟動(dòng)線程t1.start();t2.start();} }

總結(jié)

以上是生活随笔為你收集整理的Java基础day20的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。