中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁(yè) > news >正文

汽車行業(yè)網(wǎng)站建設(shè)方案深圳百度代理

汽車行業(yè)網(wǎng)站建設(shè)方案,深圳百度代理,網(wǎng)絡(luò)營(yíng)銷對(duì)企業(yè)的作用,網(wǎng)頁(yè)設(shè)計(jì)作品欣賞網(wǎng)站1. 為什么要有多線程? 線程:線程是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位。它被包含在進(jìn)程之中,是進(jìn)程中實(shí)際運(yùn)行單位。 進(jìn)程:進(jìn)程是程序的基本執(zhí)行實(shí)體。 什么是多線程? 有了多線程,我們就可以讓程序同時(shí)做…

1. 為什么要有多線程?

線程:線程是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位。它被包含在進(jìn)程之中,是進(jìn)程中實(shí)際運(yùn)行單位。

進(jìn)程:進(jìn)程是程序的基本執(zhí)行實(shí)體。

  1. 什么是多線程?

    有了多線程,我們就可以讓程序同時(shí)做多件事情。

    1. 多線程的作用?

    提高效率

    1. 多線程的應(yīng)用場(chǎng)景?

    只要你想讓多個(gè)事件同時(shí)運(yùn)行就需要多線程

    比如:軟件中的耗時(shí)操作、所有的聊天軟件、所有的服務(wù)器。

?

2. 多線程的兩個(gè)概念?

并發(fā):在同一時(shí)刻,有多個(gè)指令在單個(gè) CPU 上交替執(zhí)行

并行:在同一時(shí)刻,有多個(gè)指令在多個(gè) CPU 上同時(shí)執(zhí)行

3. 多線程的實(shí)現(xiàn)方式

1. 繼承 Thread 類的方法進(jìn)行實(shí)現(xiàn)2. 實(shí)現(xiàn) Runnable 接口的方式進(jìn)行實(shí)現(xiàn)3. 利用 Callable 接口和 Future 接口方式實(shí)現(xiàn)

多線程實(shí)現(xiàn)方式1-代碼示例:

public class MyThread extends Thread{@Overridepublic void run() {// 線程要執(zhí)行的代碼for (int i = 0; i < 100; i++) {System.out.println(getName() + "hello world");}}
}
public class ThreadDemo {public static void main(String[] args) {/*** 多線程的第一種啟動(dòng)方式*      1. 自己定義一個(gè)類繼承 Thread 類*      2. 重寫 run 方法*      3. 創(chuàng)建子類對(duì)象,并啟動(dòng)線程*/MyThread t1 = new MyThread();MyThread t2 = new MyThread();t1.setName("線程1");t2.setName("線程2");// 開(kāi)啟線程t1.start();t2.start();}
}

多線程實(shí)現(xiàn)方式2-代碼示例:

public class MyRun implements Runnable{@Overridepublic void run() {// 線程要執(zhí)行的代碼for (int i = 0; i < 100; i++) {// 獲取當(dāng)前線程對(duì)象System.out.println(Thread.currentThread().getName() + "hello world");}}
}
public class ThreadDemo {public static void main(String[] args) {/*** 多線程的第二種實(shí)現(xiàn)方式*      1. 自己定義一個(gè)類實(shí)現(xiàn) Runnable 接口*      2. 重寫里面的 run 方法*      3. 創(chuàng)建自己的類的對(duì)象。*      4. 創(chuàng)建一個(gè) Thread 類的對(duì)象,并開(kāi)啟多線程*/// 創(chuàng)建 MyRun 對(duì)象// 表示多線程要執(zhí)行的任務(wù)MyRun mr = new MyRun();// 創(chuàng)建線程對(duì)象Thread t1 = new Thread(mr);Thread t2 = new Thread(mr);// 給線程設(shè)置名字t1.setName("線程一");t2.setName("線程二");// 開(kāi)啟線程t1.start();t2.start();}
}

多線程實(shí)現(xiàn)方式3-代碼示例:

public class MyCallable implements Callable<Integer> {@Overridepublic Integer call() throws Exception {// 求 1-100 之間的和int sum = 0;for (int i = 0; i <= 100; i++) {sum = sum + i;}return sum;}
}
public class ThreadDemo {public static void main(String[] args) throws ExecutionException, InterruptedException {/*** 多線程第三種實(shí)現(xiàn)方式:*      特點(diǎn):可以獲取到多線程運(yùn)行的結(jié)果**      1. 創(chuàng)建一個(gè)類 MyCallable 實(shí)現(xiàn) Callable 接口*      2. 重寫 call(是有返回值的,表示多線程運(yùn)行的結(jié)果)*      3. 創(chuàng)建 MyCallable 的對(duì)象(表示多線程要執(zhí)行的任務(wù))*      4. 創(chuàng)建 FutureTask 的對(duì)象(作用管理多線程運(yùn)行的結(jié)果)*      5. 創(chuàng)建 Thread 類的對(duì)象,并啟動(dòng)(表示線程)*/// 創(chuàng)建 MyCallable 的對(duì)象(表示多線程要執(zhí)行的任務(wù))MyCallable mc = new MyCallable();// 創(chuàng)建 FutureTask 的對(duì)象(作用管理多線程運(yùn)行的結(jié)果)FutureTask<Integer> ft = new FutureTask<>(mc);// 創(chuàng)建線程的對(duì)象Thread t1 = new Thread(ft);// 開(kāi)啟線程t1.start();// 獲取多線程運(yùn)行的結(jié)果Integer result = ft.get();System.out.println(result);}
}

在這里插入圖片描述

4. 常見(jiàn)的成員方法

setName && currentThread && sleep

public class MyThread extends Thread{public MyThread() {}public MyThread(String name) {super(name);}@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(getName() + "@" + i);}}
}
public class ThreadDemo {public static void main(String[] args) throws InterruptedException {/*** void setName(String name)        設(shè)置線程的名字(構(gòu)造方法也可以設(shè)置名字)*      細(xì)節(jié):*          1、如果我們沒(méi)有給線程名字,線程也有默認(rèn)的名字的*              格式:Thread-X(X 序號(hào),從 0 開(kāi)始的)*          2、如果我們要給線程設(shè)置名字,可以用 set 方法進(jìn)行設(shè)置,也可以用構(gòu)造方法設(shè)置** static Thread currentThread()    獲取當(dāng)前線程對(duì)象*      細(xì)節(jié):*          當(dāng) JVM 虛擬機(jī)啟動(dòng)后,會(huì)自動(dòng)啟動(dòng)多條線程*          當(dāng)其中有一條線程就叫做 main 線程*          它的主要作用發(fā)就是調(diào)用 main 方法,并執(zhí)行里面的代碼*          在以前,我們寫的所有代碼,其實(shí)就是運(yùn)行在 main 線程當(dāng)中。* static void sleep(long time)     讓線程休眠指定的時(shí)間,單位為毫秒*      細(xì)節(jié):*          1、那條線程執(zhí)行到這個(gè)方法,那么哪條線程就會(huì)停留對(duì)應(yīng)的時(shí)間*          2、方法的參數(shù):就表示睡眠的時(shí)間,單位毫秒(1秒 = 1000毫秒)*          3、當(dāng)時(shí)間到了之后,線程就會(huì)自動(dòng)醒來(lái),繼續(xù)執(zhí)行下面的其他代碼**///setName/*// 1. 創(chuàng)建線程對(duì)象MyThread t1 = new MyThread("飛機(jī)");MyThread t2 = new MyThread("坦克");// 2. 開(kāi)啟線程t1.start();t2.start();*/// 哪條線程執(zhí)行到這個(gè)方法,此時(shí)獲取的就是哪條線程的鍍錫/*Thread t = Thread.currentThread();String name = t.getName();System.out.println(name); // main*/// sleep/*System.out.println("111111111111111");Thread.sleep(5000);System.out.println("222222222222222");*/}
}

setPriority && getPriority

public class MyRunnable implements Runnable{@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName() + "---" +i);}}
}
public class ThreadDemo {public static void main(String[] args) {/***  setPriority(int newPriority)    設(shè)置線程的優(yōu)先級(jí)*  final int getPriority()         獲取線程的優(yōu)先級(jí)*/// 創(chuàng)建線程要執(zhí)行的參數(shù)對(duì)象MyRunnable mr = new MyRunnable();// 創(chuàng)建線程對(duì)象Thread t1 = new Thread(mr, "飛機(jī)");Thread t2 = new Thread(mr, "坦克");t1.setPriority(1);t2.setPriority(10);t1.start();t2.start();}
}

守護(hù)線程

public class MyThread1 extends Thread{@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println(getName() + "@" + i);}}
}
public class MyThread2 extends Thread{@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(getName() + "@" + i);}}
}
public class ThreadDemo {public static void main(String[] args) {/*** final void setDaemon(boolean on)     設(shè)置為守護(hù)線程*      細(xì)節(jié):*          當(dāng)其他的非守護(hù)線程執(zhí)行完畢之后,守護(hù)線程就會(huì)陸續(xù)結(jié)束*      通俗易懂:*          當(dāng)女神線程結(jié)束了,那么備胎也沒(méi)有存在的必要了*/MyThread1 t1 = new MyThread1();MyThread2 t2 = new MyThread2();t1.setName("女神");t2.setName("備胎");// 把第二個(gè)線程設(shè)置為守護(hù)線程(備胎線程)t2.setDaemon(true);t1.start();t2.start();}
}

禮讓線程

public class MyThread extends Thread{@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(getName() + "@" + i);// 表示出讓當(dāng)前 CPU 的執(zhí)行權(quán),讓出執(zhí)行權(quán)的線程也會(huì)重新參與搶奪。Thread.yield();}}
}
public class ThreadDemo {public static void main(String[] args) {/*** public static void yield()       出讓線程/禮讓線程*/MyThread t1 = new MyThread();MyThread t2 = new MyThread();t1.setName("飛機(jī)");t2.setName("坦克");t1.start();t2.start();}
}

插入線程

public class MyThread extends Thread{@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(getName() + "@" + i);}}
}
public class ThreadDemo {public static void main(String[] args) throws InterruptedException {/*** public final void join()     插入線程/插隊(duì)線程*/MyThread t = new MyThread();t.setName("土豆");t.start();// 把 t 線程插入到當(dāng)前線程之前。// t:土豆// 當(dāng)前線程:maint.join();// 執(zhí)行在 main 線程中的方法for (int i = 0; i < 10; i++) {System.out.println("main 線程" + i);}}
}

線程的生命周期

在這里插入圖片描述

5. 線程安全問(wèn)題

public class MyThread extends Thread{// static 表示這個(gè)類所有的對(duì)象都共享 ticketint ticket = 0;  // 0 ~ 99@Overridepublic void run() {while (true) {if (ticket < 100) {try {sleep(100);} catch (InterruptedException e) {e.printStackTrace();}ticket++;System.out.println(getName() + "正在賣" + ticket + "張票!!!");} else {break;}}}
}
public class ThreadDemo {public static void main(String[] args) {/*** 需求:*      某電影院目前正在上映國(guó)產(chǎn)大片,共 100 張票,而它有 3 個(gè)窗口賣票,請(qǐng)?jiān)O(shè)計(jì)一個(gè)程序模擬該電影院賣票。*/// 創(chuàng)建線程對(duì)象MyThread t1 = new MyThread();MyThread t2 = new MyThread();MyThread t3 = new MyThread();// 起名字t1.setName("窗口一");t2.setName("窗口二");t3.setName("窗口三");// 開(kāi)啟線程t1.start();t2.start();t3.start();}
}

上面的代碼存在以下問(wèn)題:

  1. 超賣:線程1、2、3都有可能在同時(shí)查看剩余票數(shù)時(shí),都看到還有可賣的票,于是同時(shí)執(zhí)行買票操作。
  2. 賣出相同的票:因?yàn)樵诰€程1、2、3都有可能同一時(shí)間進(jìn)行買票操作

同步代碼塊解決線程安全問(wèn)題

格式:

synchronized () {操作共享數(shù)據(jù)的代碼
}

特點(diǎn)1:鎖默認(rèn)打開(kāi),有一個(gè)線程進(jìn)去了,鎖會(huì)自動(dòng)關(guān)閉

特點(diǎn)2:里面的代碼全部執(zhí)行完畢,線程出來(lái),鎖自動(dòng)打開(kāi)

修改之后的線程代碼

public class MyThread extends Thread{// static 表示這個(gè)類所有的對(duì)象都共享 ticketstatic int ticket = 0;  // 0 ~ 99// 加 static 保證 obj 是唯一的。(鎖對(duì)象要保證是唯一的)static Object obj = new Object();@Overridepublic void run() {while (true) {// 同步代碼塊synchronized (obj) { // 這里的 obj 也可以替換成 MyThread.class(MyThread 的字節(jié)碼文件),因?yàn)?MyThread 的字節(jié)碼文件也是唯一的。 if (ticket < 100) {try {sleep(10);} catch (InterruptedException e) {e.printStackTrace();}ticket++;System.out.println(getName() + "正在賣" + ticket + "張票!!!");} else {break;}}}}
}

注意:鎖要加在 while 循環(huán)的里面,如果加在循環(huán)的外面,某個(gè)線程搶到鎖后,會(huì)一直執(zhí)行循環(huán)內(nèi)的代碼,直到這個(gè)線程把所有的票買完。因?yàn)榫€程搶到票之后,就算其它線程也搶到票,也只能在循環(huán)鎖外面等著。

同步方法

格式:修飾符 synchronized 返回值類型 方法名(方法參數(shù)) {…}

特點(diǎn)1:同步方法是鎖住方法里面的代碼

特點(diǎn)2:鎖對(duì)象不能自己指定

  • 非靜態(tài):this
  • 靜態(tài):當(dāng)前類的字節(jié)碼文件對(duì)象

StringBuffer 與 StringBuilder 的線程安全區(qū)別

  • StringBuffer 是線程安全的。因?yàn)樵?StringBuffer 中有 synchronized 關(guān)鍵字。

  • 而 StringBuilder 則不是線程安全的。
    在這里插入圖片描述

    那對(duì) StringBuffer 和 StringBuilder 我們?nèi)绾芜x擇?

    • 代碼是單線程的,不涉及多線程、線程安全的問(wèn)題,那么選擇 StringBuilder 就好了。
    • 如果是多線程,設(shè)計(jì)線程安全問(wèn)題,那么可以選擇 StringBuffer 。

6. 死鎖

6.1 鎖 lock

  1. 示例代碼

    // 創(chuàng)建鎖對(duì)象
    Lock lock = new ReentrantLock();
    // 設(shè)置鎖
    lock.lock();
    // 釋放鎖
    lock.unlock();
    
  2. 鎖的應(yīng)用

    public class MyThread extends Thread{static int ticket = 0;// 加 static 使每個(gè)線程都用統(tǒng)一把鎖static Lock lock = new ReentrantLock();@Overridepublic void run() {// 1. 循環(huán)while (true) {// 2. 同步代碼塊lock.lock();try {// 3. 判斷if (ticket == 100) {break;} else {// 4. 判斷Thread.sleep(10);ticket++;System.out.println(getName() + "在賣第" + ticket + "張票");}} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}}
    }
    
    public class ThreadDemo {public static void main(String[] args) {/*** 需求:*      某電影院目前正在上映國(guó)產(chǎn)大片,共 100 張票,而它有 3 個(gè)窗口賣票,請(qǐng)?jiān)O(shè)計(jì)一個(gè)程序模擬該電影院賣票。**      利用同步方法完成**/MyThread t1 = new MyThread();MyThread t2 = new MyThread();MyThread t3 = new MyThread();t1.setName("窗口1");t2.setName("窗口2");t3.setName("窗口3");t1.start();t2.start();t3.start();}
    }
    

6.2 死鎖

  • 死鎖示例代碼
public class MyThread extends Thread{static Object objA = new Object();static Object objB = new Object();@Overridepublic void run() {// 1. 循環(huán)while (true) {if ("線程A".equals(getName())) {synchronized (objA) {System.out.println("線程 A 拿到了 A 鎖,準(zhǔn)備拿 B 鎖");synchronized (objB) {System.out.println("線程 A 拿到了 B 鎖,順利執(zhí)行完一輪");}}} else if ("線程B".equals(getName())) {if ("線程B".equals(getName())) {synchronized (objB) {System.out.println("線程 B 拿到了 B 鎖,準(zhǔn)備拿 A 鎖");synchronized (objA) {System.out.println("線程 B 拿到了 A 鎖,順利執(zhí)行完一輪");}}}}}}
}
public class ThreadDemo {public static void main(String[] args) {/*** 死鎖*/MyThread t1 = new MyThread();MyThread t2 = new MyThread();t1.setName("線程A");t2.setName("線程B");t1.start();t2.start();}
}

執(zhí)行這個(gè)代碼就會(huì)出現(xiàn)死鎖的情況。

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

7.1 等待喚醒機(jī)制

等待喚醒機(jī)制思路(Desk、Cook、Foodie)
在這里插入圖片描述

示例代碼(寫法一):

public class Desk {/*** 作用:控制生產(chǎn)者和消費(fèi)者的執(zhí)行*/// 是否有面條 0:沒(méi)有面條 1:有面條public static int foodFlog = 0;// 總個(gè)數(shù)public static int count = 10;// 鎖對(duì)象public static Object lock = new Object();
}
public class Cook extends Thread{@Overridepublic void run() {/*** 1. 循環(huán)* 2. 同步代碼塊* 3. 判斷共享數(shù)據(jù)是否到了尾聲(到了尾聲)* 4. 判斷共享數(shù)據(jù)是否到了尾聲(沒(méi)有到尾聲,執(zhí)行核心邏輯)*/while (true) {synchronized (Desk.lock) {if (Desk.count == 0) {break;} else {// 判斷桌子上是否有食物// 如果有,就等待if (Desk.foodFlog == 1) {try {Desk.lock.wait();} catch (InterruptedException e) {e.printStackTrace();}} else {// 如果沒(méi)有,就制作食物System.out.println("廚師做了一碗面條");// 修改桌子上的食物狀態(tài)Desk.foodFlog = 1;// 叫醒等待的消費(fèi)者開(kāi)吃Desk.lock.notifyAll();}}}}}
}
public class Foodie extends Thread{@Overridepublic void run() {/*** 1. 循環(huán)* 2. 同步代碼塊* 3. 判斷共享數(shù)據(jù)是否到了末尾(到了末尾)* 4. 判斷共享數(shù)據(jù)是否到了末尾(沒(méi)到末尾,執(zhí)行核心邏輯)*/while (true) {synchronized (Desk.lock) {if (Desk.count == 0) {break;} else {// 先判斷桌子上是否有面條if (Desk.foodFlog == 0) {// 如果沒(méi)有,就等待try {Desk.lock.wait();  // 讓當(dāng)前線程跟鎖進(jìn)行綁定} catch (InterruptedException e) {e.printStackTrace();}} else {// 把吃的總數(shù) -1Desk.count--;// 如果有,就開(kāi)吃System.out.println("吃貨正在吃面條,還能再吃" + Desk.count + "碗!!!");// 吃完之后,喚醒廚師繼續(xù)做Desk.lock.notifyAll();// 修改桌子的狀態(tài)Desk.foodFlog = 0;}}}}}
}

示例代碼(寫法二 — 阻塞隊(duì)列方式實(shí)現(xiàn)):

? 阻塞隊(duì)列的繼承結(jié)構(gòu)
在這里插入圖片描述

public class Cook extends Thread{ArrayBlockingQueue<String> queue;public Cook(ArrayBlockingQueue<String> queue) {this.queue = queue;}@Overridepublic void run() {while (true) {// 不斷的把面條放到阻塞隊(duì)列中try {queue.put("面條");System.out.println("廚師放了一碗面條");} catch (InterruptedException e) {e.printStackTrace();}}}
}
public class Foodie extends Thread{ArrayBlockingQueue<String> queue;public Foodie(ArrayBlockingQueue<String> queue) {this.queue = queue;}@Overridepublic void run() {while (true) {// 不斷從阻塞隊(duì)列中獲取面條try {String food = queue.take();System.out.println(food);} catch (InterruptedException e) {e.printStackTrace();}}}
}
public class ThreadDemo {public static void main(String[] args) {/*** 需求:利用阻塞隊(duì)列完成生產(chǎn)者和消費(fèi)者(等待喚醒機(jī)制)的代碼** 細(xì)節(jié):*      生產(chǎn)者和消費(fèi)者必須使用同一個(gè)阻塞隊(duì)列*/// 1. 創(chuàng)建阻塞隊(duì)列的對(duì)象ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(1);// 2. 創(chuàng)建線程的對(duì)象,并把阻塞隊(duì)列傳遞過(guò)去Cook c = new Cook(queue);Foodie f = new Foodie(queue);// 3. 開(kāi)啟線程c.start();f.start();}
}

7.2 線程的狀態(tài)

在這里插入圖片描述

但是再 JVM 里面是沒(méi)有定義運(yùn)行狀態(tài)的
在這里插入圖片描述

8. 練習(xí)

8.1 多線程實(shí)現(xiàn)搶紅包

public class MyThread extends Thread{// 共享數(shù)據(jù)// 100 塊,分成了3個(gè)紅包static double money = 100;static int count = 3;// 最小的中獎(jiǎng)金額static final double MIN = 0;@Overridepublic void run() {// 同步代碼塊synchronized (MyThread.class) {if (count == 0) {// 判斷,共享數(shù)據(jù)是否到了末尾(已經(jīng)到末尾)System.out.println(getName() + "沒(méi)有搶到紅包!");} else {// 判斷,共享數(shù)據(jù)是否到了末尾(沒(méi)有到末尾)// 定義一個(gè)變量,表示中獎(jiǎng)金額double prize = 0;if (count == 1) {// 表示此時(shí)是最后一個(gè)紅包// 就無(wú)需隨機(jī),剩余所有的錢都是中獎(jiǎng)金額prize = money;} else {// 表示第一次,第二次(隨機(jī))Random r = new Random();double bounds = money - (count - 1) * MIN;prize = r.nextDouble(bounds);if (prize < MIN) {prize = MIN;}}// 從 money 中去掉當(dāng)前中獎(jiǎng)的金額money = money - prize;// 紅包的個(gè)數(shù) -1count--;// 本次紅包的信息進(jìn)行打印System.out.println(getName() + "搶到了" + prize + "元");}}}
}
public class Test {public static void main(String[] args) {/*** 微信中的搶紅包也用了多線程。* 假設(shè):100塊,分成了3個(gè)包,現(xiàn)在有5個(gè)人去搶。* 其中,紅包是共享數(shù)據(jù)。* 5個(gè)人是5條線程* 打印結(jié)果如下:*      xxx 搶到了 xxx 元*      xxx 搶到了 xxx 元*      xxx 沒(méi)搶到*      xxx 沒(méi)搶到**/// 創(chuàng)建線程對(duì)象MyThread t1 = new MyThread();MyThread t2 = new MyThread();MyThread t3 = new MyThread();MyThread t4 = new MyThread();MyThread t5 = new MyThread();// 給線程設(shè)置名字t1.setName("小A");t2.setName("小B");t3.setName("小C");t4.setName("小D");t5.setName("小E");// 啟動(dòng)線程t1.start();t2.start();t3.start();t4.start();t5.start();}
}

8.2 多線程實(shí)現(xiàn)抽獎(jiǎng)

public class MyThread extends Thread{ArrayList<Integer> list;public MyThread(ArrayList<Integer> list) {this.list = list;}@Overridepublic void run() { // 1  // 2// 循環(huán)// 同步代碼塊// 判斷// 判斷while (true) {synchronized (MyThread.class) {if (list.size() == 0) {break;} else {// 繼續(xù)抽獎(jiǎng)Collections.shuffle(list);int price = list.remove(0);System.out.println(getName() + "又產(chǎn)生了一個(gè) " + price + " 元大獎(jiǎng)");}}try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}}}
}
public class Test {public static void main(String[] args) {/*** 有一個(gè)抽獎(jiǎng)池,該抽獎(jiǎng)池中存放了獎(jiǎng)勵(lì)的金額,該抽獎(jiǎng)池中的獎(jiǎng)項(xiàng)為{18,5,20,50,100,200,500,800,2,80,300,700);* 創(chuàng)建兩個(gè)抽獎(jiǎng)箱(線程)設(shè)置線程名稱分別為“抽獎(jiǎng)箱1”,“抽獎(jiǎng)箱2”* 隨機(jī)從抽獎(jiǎng)池中獲取獎(jiǎng)項(xiàng)元素并打印在控制臺(tái)上,格式如下:*      每次抽出一個(gè)獎(jiǎng)項(xiàng)就打印一個(gè)(隨機(jī))* 抽獎(jiǎng)箱1 又產(chǎn)生了一個(gè) 10 元大獎(jiǎng)* 抽獎(jiǎng)箱1 又產(chǎn)生了一個(gè) 100 元大獎(jiǎng)* 抽獎(jiǎng)箱1 又產(chǎn)生了一個(gè) 200 元大獎(jiǎng)* 抽獎(jiǎng)箱1 又產(chǎn)生了一個(gè) 800 元大獎(jiǎng)* 元大獎(jiǎng)抽獎(jiǎng)箱2 又產(chǎn)生了一個(gè) 700* ......*/// 創(chuàng)建獎(jiǎng)池ArrayList<Integer> list = new ArrayList<>();Collections.addAll(list, 18,5,20,50,100,200,500,800,2,80,300,700);// 創(chuàng)建線程MyThread t1 = new MyThread(list);MyThread t2 = new MyThread(list);// 設(shè)置名字t1.setName("抽獎(jiǎng)箱1");t2.setName("抽獎(jiǎng)箱2");// 啟動(dòng)線程t1.start();t2.start();}
}

8.3 多線程統(tǒng)計(jì)并求最大值(解法1)

public class MyThread extends Thread{ArrayList<Integer> list;public MyThread(ArrayList<Integer> list) {this.list = list;}// 線程1static ArrayList<Integer> list1 = new ArrayList<>();// 線程2static ArrayList<Integer> list2 = new ArrayList<>();@Overridepublic void run() { // 1  // 2// 循環(huán)// 同步代碼塊// 判斷// 判斷while (true) {synchronized (MyThread.class) {if (list.size() == 0) {if ("抽獎(jiǎng)箱1".equals(getName())) {System.out.println("抽獎(jiǎng)箱1" + list1);} else {System.out.println("抽獎(jiǎng)箱2" + list2);}break;} else {// 繼續(xù)抽獎(jiǎng)Collections.shuffle(list);int price = list.remove(0);if ("抽獎(jiǎng)箱1".equals(getName())) {list1.add(price);} else {list2.add(price);}}}try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}}}
}
public class Test {public static void main(String[] args) {/*** 有一個(gè)抽獎(jiǎng)池,該抽獎(jiǎng)池中存放了獎(jiǎng)勵(lì)的金額,該抽獎(jiǎng)池中的獎(jiǎng)項(xiàng)為{10,5,20,50,100,200,500,800,2,80,300,700};* 創(chuàng)建兩個(gè)抽獎(jiǎng)箱(線程)設(shè)置線程名稱分別為“抽獎(jiǎng)箱1”,“抽獎(jiǎng)箱2”* 隨機(jī)從抽獎(jiǎng)池中獲取獎(jiǎng)項(xiàng)元素并打印在控制臺(tái)上,格式如下:* 每次抽的過(guò)程中,不打印,抽完時(shí)一次性打印(隨機(jī))     在此次抽獎(jiǎng)過(guò)程中,抽獎(jiǎng)箱1總共產(chǎn)生了6個(gè)獎(jiǎng)項(xiàng)。*      分別為: 10,20,100,500,2,300最高獎(jiǎng)項(xiàng)為300元,總計(jì)額為932元* 在此次抽獎(jiǎng)過(guò)程中,抽獎(jiǎng)箱2總共產(chǎn)生了6個(gè)獎(jiǎng)項(xiàng)。*      分別為: 5,50,200,800,80,700最高獎(jiǎng)項(xiàng)為800元,總計(jì)額為1835元*/// 創(chuàng)建獎(jiǎng)池ArrayList<Integer> list = new ArrayList<>();Collections.addAll(list, 18,5,20,50,100,200,500,800,2,80,300,700);// 創(chuàng)建線程MyThread t1 = new MyThread(list);MyThread t2 = new MyThread(list);// 設(shè)置名字t1.setName("抽獎(jiǎng)箱1");t2.setName("抽獎(jiǎng)箱2");// 啟動(dòng)線程t1.start();t2.start();}
}

8.4 多線程統(tǒng)計(jì)并求最大值(解法2)

public class MyThread extends Thread{ArrayList<Integer> list;public MyThread(ArrayList<Integer> list) {this.list = list;}@Overridepublic void run() {ArrayList<Integer> boxList = new ArrayList<>();while (true) {synchronized (MyThread.class) {if (list.size() == 0) {System.out.println(getName() + boxList);break;} else {// 繼續(xù)抽獎(jiǎng)Collections.shuffle(list);int price = list.remove(0);boxList.add(price);}}try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}}}
}
public class Test {public static void main(String[] args) {/*** 有一個(gè)抽獎(jiǎng)池,該抽獎(jiǎng)池中存放了獎(jiǎng)勵(lì)的金額,該抽獎(jiǎng)池中的獎(jiǎng)項(xiàng)為{10,5,20,50,100,200,500,800,2,80,300,700};* 創(chuàng)建兩個(gè)抽獎(jiǎng)箱(線程)設(shè)置線程名稱分別為“抽獎(jiǎng)箱1”,“抽獎(jiǎng)箱2”* 隨機(jī)從抽獎(jiǎng)池中獲取獎(jiǎng)項(xiàng)元素并打印在控制臺(tái)上,格式如下:* 每次抽的過(guò)程中,不打印,抽完時(shí)一次性打印(隨機(jī))     在此次抽獎(jiǎng)過(guò)程中,抽獎(jiǎng)箱1總共產(chǎn)生了6個(gè)獎(jiǎng)項(xiàng)。*      分別為: 10,20,100,500,2,300最高獎(jiǎng)項(xiàng)為300元,總計(jì)額為932元* 在此次抽獎(jiǎng)過(guò)程中,抽獎(jiǎng)箱2總共產(chǎn)生了6個(gè)獎(jiǎng)項(xiàng)。*      分別為: 5,50,200,800,80,700最高獎(jiǎng)項(xiàng)為800元,總計(jì)額為1835元*/// 創(chuàng)建獎(jiǎng)池ArrayList<Integer> list = new ArrayList<>();Collections.addAll(list, 18,5,20,50,100,200,500,800,2,80,300,700);// 創(chuàng)建線程MyThread t1 = new MyThread(list);MyThread t2 = new MyThread(list);// 設(shè)置名字t1.setName("抽獎(jiǎng)箱1");t2.setName("抽獎(jiǎng)箱2");// 啟動(dòng)線程t1.start();t2.start();}
}

8.4 多線程之間的比較

public class MyCallable implements Callable<Integer> {ArrayList<Integer> list;public MyCallable(ArrayList<Integer> list) {this.list = list;}@Overridepublic Integer call() throws Exception {ArrayList<Integer> boxList = new ArrayList<>();while (true) {synchronized (MyCallable.class) {if (list.size() == 0) {System.out.println(Thread.currentThread().getName() + boxList);break;} else {// 繼續(xù)抽獎(jiǎng)Collections.shuffle(list);int price = list.remove(0);boxList.add(price);}}Thread.sleep(10);}// 把集合中的最大值返回if (boxList.size() == 0) {return null;} else {return Collections.max(boxList);}}
}
public class Test {public static void main(String[] args) throws ExecutionException, InterruptedException {/*** 有一個(gè)抽獎(jiǎng)池,該抽獎(jiǎng)池中存放了獎(jiǎng)勵(lì)的金額,該抽獎(jiǎng)池中的獎(jiǎng)項(xiàng)為{10,5,20,50,100,200,500,800,2,80,300,700};* 創(chuàng)建兩個(gè)抽獎(jiǎng)箱(線程)設(shè)置線程名稱分別為     "抽獎(jiǎng)箱1","抽獎(jiǎng)箱2"* 隨機(jī)從抽獎(jiǎng)池中獲取獎(jiǎng)項(xiàng)元素并打印在控制臺(tái)上,格式如下:* 在此次抽獎(jiǎng)過(guò)程中,抽獎(jiǎng)箱1總共產(chǎn)生了6個(gè)獎(jiǎng)項(xiàng),分別為: 10,20,100,500,2,300*      最高獎(jiǎng)項(xiàng)為300元,總計(jì)額為932元** 在此次抽獎(jiǎng)過(guò)程中,抽獎(jiǎng)箱2總共產(chǎn)生了6個(gè)獎(jiǎng)項(xiàng),分別為: 5,50,200,800,80,700*      最高獎(jiǎng)項(xiàng)為800元,總計(jì)額為1835元** 在此次抽獎(jiǎng)過(guò)程中,抽獎(jiǎng)箱2中產(chǎn)生了最大獎(jiǎng)項(xiàng),該獎(jiǎng)項(xiàng)金額為800元*  核心邏輯:獲取線程抽獎(jiǎng)的最大值(看成是線程運(yùn)行的結(jié)果)* 以上打印效果只是數(shù)據(jù)模擬,實(shí)際代碼運(yùn)行的效果會(huì)有差異*/// 創(chuàng)建獎(jiǎng)池ArrayList<Integer> list = new ArrayList<>();Collections.addAll(list, 10,5,20,50,100,200,500,800,2,80,300,700);// 創(chuàng)建多線程要運(yùn)行的參數(shù)對(duì)象MyCallable mc = new MyCallable(list);// 創(chuàng)建多線程運(yùn)行結(jié)果的管理對(duì)象FutureTask<Integer> ft1 = new FutureTask<>(mc);FutureTask<Integer> ft2 = new FutureTask<>(mc);// 創(chuàng)建線程對(duì)象Thread t1 = new Thread(ft1);Thread t2 = new Thread(ft2);// 設(shè)置名字t1.setName("抽獎(jiǎng)箱1");t2.setName("抽獎(jiǎng)箱2");// 開(kāi)啟線程t1.start();t2.start();Integer max1 = ft1.get();Integer max2 = ft2.get();System.out.println(max1);System.out.println(max2);// 在此次抽獎(jiǎng)過(guò)程中,抽獎(jiǎng)箱2中產(chǎn)生了最大獎(jiǎng)項(xiàng),該獎(jiǎng)項(xiàng)金額為800元System.out.println("在此次抽獎(jiǎng)過(guò)程中,抽獎(jiǎng)箱"+(ft1.get()==800?t1.getName():t2.getName())+"中產(chǎn)生了最大獎(jiǎng)項(xiàng),該獎(jiǎng)項(xiàng)金額為800元");}
}

9. 線程池

9.1 以前寫多線程的弊端

  • 弊端1:用到線程就得創(chuàng)建
  • 弊端2:用完之后線程就消失

9.3 線程池主要核心原理

  1. 創(chuàng)建一個(gè)池子,池子中是空的
  2. 提交任務(wù)時(shí),池子會(huì)創(chuàng)建新的線程對(duì)象,任務(wù)執(zhí)行完畢,線程歸還給池子,下回再次提交任務(wù)時(shí),不需要?jiǎng)?chuàng)建新的線程,直接復(fù)用已有的線程即可。
  3. 但是如果提交任務(wù)的時(shí)候,池子中沒(méi)有空閑的線程,也無(wú)法創(chuàng)建新的線程,任務(wù)就會(huì)排隊(duì)等待。

9.3 線程池代碼實(shí)現(xiàn)

  1. 創(chuàng)建線程池
  2. 提交任務(wù)
  3. 所有任務(wù)全部執(zhí)行完畢,關(guān)閉線程池

newCachedThreadPool 演示

public class MyThreadPoolDemo {public static void main(String[] args) throws InterruptedException {/*** public static ExecutorService newCachedThreadPool()              創(chuàng)建一個(gè)沒(méi)有上限的線程池* public static ExecutorService newFixedThreadPool(int nThreads)   創(chuàng)建有上線的線程池*/// newCachedThreadPool 演示// 1. 獲取線程池的對(duì)象ExecutorService pool1 = Executors.newCachedThreadPool();Thread.sleep(1000);// 2. 提交任務(wù)pool1.submit(new MyRunnable());Thread.sleep(1000);pool1.submit(new MyRunnable());Thread.sleep(1000);pool1.submit(new MyRunnable());Thread.sleep(1000);pool1.submit(new MyRunnable());Thread.sleep(1000);pool1.submit(new MyRunnable());// 3. 銷毀線程池
//        pool1.shutdown();}
}
public class MyRunnable implements Runnable{@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "---");}
}

在這里插入圖片描述

運(yùn)行效果:可以看到會(huì)一直在服用線程池中的線程1。

newFixedThreadPool 演示

public class MyThreadPoolDemo {public static void main(String[] args) throws InterruptedException {/*** public static ExecutorService newCachedThreadPool()              創(chuàng)建一個(gè)沒(méi)有上限的線程池* public static ExecutorService newFixedThreadPool(int nThreads)   創(chuàng)建有上線的線程池*/// newFixedThreadPool 演示// 1. 獲取線程池的對(duì)象ExecutorService pool1 = Executors.newFixedThreadPool(3);// 2. 提交任務(wù)pool1.submit(new MyRunnable());pool1.submit(new MyRunnable());pool1.submit(new MyRunnable());pool1.submit(new MyRunnable());pool1.submit(new MyRunnable());// 3. 銷毀線程池
//        pool1.shutdown();}
}
public class MyRunnable implements Runnable{@Overridepublic void run() {for (int i = 1; i <= 100; i++) {System.out.println(Thread.currentThread().getName() + "---" + i);}}
}

在這里插入圖片描述
在運(yùn)行的結(jié)果可以看到雖然 new 的線程大于3個(gè),但是實(shí)際生成的線程只有3個(gè)。

或者我們可以使用 DEBUG 的方式查看結(jié)果
在這里插入圖片描述

在長(zhǎng)度為3的線程池中,創(chuàng)建了4個(gè)線程之后,線程池的長(zhǎng)度為3,在外面的等待的任務(wù)數(shù)為1。

9.4 自定義線程池詳解

在這里插入圖片描述
在這里插入圖片描述
注意:Java 默認(rèn)的任務(wù)拒絕策略是 AbortPolicy,默認(rèn)策略:丟棄任務(wù)并拋出 PejectdExecutionException 異常

拒接策略
在這里插入圖片描述
創(chuàng)建自定義線程的構(gòu)造方法參數(shù)解析:
在這里插入圖片描述
自定義線程池小結(jié):

  1. 當(dāng)核心線程滿時(shí),再提交任務(wù)就會(huì)排隊(duì)
  2. 當(dāng)核心線程滿,隊(duì)伍滿時(shí),會(huì)創(chuàng)建臨時(shí)線程
  3. 當(dāng)核心線程滿時(shí),隊(duì)伍滿,臨時(shí)線程滿時(shí),會(huì)觸發(fā)任務(wù)策略
學(xué)習(xí)視頻:https://www.bilibili.com/video/BV1LG4y1T7n2?p=1&vd_source=6108736e361d963b64f872fefb8bc1e7
http://www.risenshineclean.com/news/8488.html

相關(guān)文章:

  • 某男神去年年底來(lái)某網(wǎng)站做見(jiàn)面會(huì)_竟要求安保人數(shù)超過(guò)兩位數(shù)上海網(wǎng)站排名優(yōu)化怎么做
  • 做文案需要用到的網(wǎng)站站長(zhǎng)工具搜索
  • 南京網(wǎng)站建設(shè)公司關(guān)鍵詞優(yōu)化推廣公司哪家好
  • 做網(wǎng)站需要的電腦配置谷歌seo推廣公司
  • 電子商務(wù)網(wǎng)站建設(shè)與管理相關(guān)文獻(xiàn)網(wǎng)站seo博客
  • 長(zhǎng)春小學(xué)網(wǎng)站建設(shè)產(chǎn)品推廣計(jì)劃書怎么寫
  • 一站式網(wǎng)站手機(jī)端怎么做搜索引擎優(yōu)化需要多少錢
  • 在建設(shè)局網(wǎng)站上怎么樣總監(jiān)解鎖seo算法入門教程
  • wordpress 企業(yè) 模板 下載windows優(yōu)化大師卸載
  • 手機(jī)網(wǎng)站制作 尺寸百度銷售推廣
  • 如何用網(wǎng)站做淘寶聯(lián)盟怎么讓關(guān)鍵詞快速上首頁(yè)
  • wordpress安裝幻燈片seo價(jià)格是多少
  • 打開(kāi)一個(gè)網(wǎng)站在建設(shè)中知乎營(yíng)銷推廣
  • 南京淄博網(wǎng)站建設(shè)方案?jìng)€(gè)人對(duì)網(wǎng)絡(luò)營(yíng)銷的看法
  • 怎么做網(wǎng)站旺鋪裝修東莞seo推廣機(jī)構(gòu)帖子
  • 現(xiàn)成的手機(jī)網(wǎng)站做APP深圳百度首頁(yè)優(yōu)化
  • 西數(shù) 網(wǎng)站建設(shè)文件關(guān)鍵詞搜索工具
  • 網(wǎng)站建設(shè)客戶常問(wèn)到的問(wèn)題網(wǎng)站制作流程和方法
  • b2b采購(gòu)平臺(tái)網(wǎng)站正規(guī)推廣平臺(tái)有哪些
  • 網(wǎng)站開(kāi)發(fā)技術(shù)服務(wù)合同范本愛(ài)站網(wǎng)官網(wǎng)關(guān)鍵詞
  • 如何做產(chǎn)品網(wǎng)站的推廣樂(lè)事薯片軟文推廣
  • 唐山模板網(wǎng)站建設(shè)重慶企業(yè)seo
  • 網(wǎng)站建設(shè)與管理課程長(zhǎng)沙排名優(yōu)化公司
  • 唐山做網(wǎng)站公司哪家好按效果付費(fèi)的網(wǎng)絡(luò)推廣方式
  • 天津市住房和城鄉(xiāng)建設(shè)委員會(huì)官方網(wǎng)站app推廣方法
  • 聊城專業(yè)做網(wǎng)站網(wǎng)絡(luò)推廣有效果嗎
  • 動(dòng)態(tài)網(wǎng)站建設(shè)流程圖包括哪些內(nèi)容
  • 順德網(wǎng)站建設(shè)策劃做網(wǎng)站多少錢
  • 網(wǎng)站建設(shè)特效大全百度推廣一般要多少錢
  • 深圳企業(yè)網(wǎng)站建設(shè)制作設(shè)計(jì)公司今日新聞國(guó)內(nèi)大事件