国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

什么是Java多線程?

高璐 / 1179人閱讀

摘要:是不能直接調(diào)用系統(tǒng)功能的,所以,我們沒有辦法直接實(shí)現(xiàn)多線程程序。通過查看,我們知道了有種方式實(shí)現(xiàn)多線程程序。使用的是搶占式調(diào)度模型演示如何設(shè)置和獲取線程優(yōu)先級返回線程對象的優(yōu)先級更改線程的優(yōu)先級線程默認(rèn)優(yōu)先級是。線程優(yōu)先級的范圍是。

第五階段 多線程 前言:

</>復(fù)制代碼

  1. 一個(gè)場景:周末,帶著并不存在的女票去看電影,無論是現(xiàn)場買票也好,又或是手機(jī)買票也好,上一秒還有位置,遲鈍了一下以后,就顯示該座位已經(jīng)無法選中,一不留神就沒有座位了,影院的票是一定的,但是究竟是如何做到,多個(gè)窗口或者用戶同時(shí)出票而又不重復(fù)的呢? 這就是我們今天所要講解的多線程問題
(一) 線程和進(jìn)程的概述 (1) 進(jìn)程

進(jìn)程:進(jìn)程是系統(tǒng)進(jìn)行資源分配和調(diào)用的獨(dú)立單位。每一個(gè)進(jìn)程都有它自己的內(nèi)存空間和系統(tǒng)資源

多線程:在同一個(gè)時(shí)間段內(nèi)可以執(zhí)行多個(gè)任務(wù),提高了CPU的使用率

(2) 線程

線程:進(jìn)程的執(zhí)行單元,執(zhí)行路徑

單線程:一個(gè)應(yīng)用程序只有一條執(zhí)行路徑

多線程:一個(gè)應(yīng)用程序有多條執(zhí)行路徑

多進(jìn)程的意義?—— 提高CPU的使用率

多線程的意義? —— 提高應(yīng)用程序的使用率

(3) 補(bǔ)充

并行和并發(fā)

并行是物理上同時(shí)發(fā)生,指在某一個(gè)時(shí)間點(diǎn)同時(shí)運(yùn)行多個(gè)程序

并發(fā)是邏輯上同時(shí)發(fā)生,指在某一個(gè)時(shí)間段內(nèi)同時(shí)運(yùn)行多個(gè)程序

Java程序運(yùn)行原理和JVM的啟動(dòng)是否是多線程的 ?

Java程序的運(yùn)行原理:

由java命令啟動(dòng)JVM,JVM啟動(dòng)就相當(dāng)于啟動(dòng)了一個(gè)進(jìn)程

接著有該進(jìn)程創(chuàng)建了一個(gè)主線程去調(diào)用main方法

JVM虛擬機(jī)的啟動(dòng)是單線程的還是多線程的 ?

垃圾回收線程也要先啟動(dòng),否則很容易會出現(xiàn)內(nèi)存溢出

現(xiàn)在的垃圾回收線程加上前面的主線程,最低啟動(dòng)了兩個(gè)線程,所以,jvm的啟動(dòng)其實(shí)是多線程的

JVM啟動(dòng)至少啟動(dòng)了垃圾回收線程和主線程,所以是多線程的

(二) 多線程代碼實(shí)現(xiàn)

需求:我們要實(shí)現(xiàn)多線程的程序。

如何實(shí)現(xiàn)呢?

由于線程是依賴進(jìn)程而存在的,所以我們應(yīng)該先創(chuàng)建一個(gè)進(jìn)程出來。

而進(jìn)程是由系統(tǒng)創(chuàng)建的,所以我們應(yīng)該去調(diào)用系統(tǒng)功能創(chuàng)建一個(gè)進(jìn)程。

Java是不能直接調(diào)用系統(tǒng)功能的,所以,我們沒有辦法直接實(shí)現(xiàn)多線程程序。

但是呢?Java可以去調(diào)用C/C++寫好的程序來實(shí)現(xiàn)多線程程序。

由C/C++去調(diào)用系統(tǒng)功能創(chuàng)建進(jìn)程,然后由Java去調(diào)用這樣的東西,

然后提供一些類供我們使用。我們就可以實(shí)現(xiàn)多線程程序了。

通過查看API,我們知道了有2種方式實(shí)現(xiàn)多線程程序。

方式1:繼承Thread類

步驟:

自定義MyThread(自定義類名)繼承Thread類

MyThread類中重寫run()

創(chuàng)建對象

啟動(dòng)線程

</>復(fù)制代碼

  1. public class MyThread extends Thread{
  2. public MyThread() {
  3. }
  4. @Override
  5. public void run() {
  6. for (int i = 0; i < 100; i++){
  7. System.out.println(getName() + ":" + i);
  8. }
  9. }
  10. }

</>復(fù)制代碼

  1. public class MyThreadTest {
  2. public static void main(String[] args) {
  3. //創(chuàng)建線程對象
  4. MyThread my = new MyThread();
  5. //啟動(dòng)線程,run()相當(dāng)于普通方法的調(diào)用,單線程效果
  6. //my.run();
  7. //首先啟動(dòng)了線程,然后再由jvm調(diào)用該線程的run()方法,多線程效果
  8. my.start();
  9. //兩個(gè)線程演示,多線程效果需要?jiǎng)?chuàng)建多個(gè)對象而不是一個(gè)對象多次調(diào)用start()方法
  10. MyThread my1 = new MyThread();
  11. MyThread my2 = new MyThread();
  12. my1.start();
  13. my2.start();
  14. }
  15. }
  16. //運(yùn)行結(jié)果
  17. Thread-1:0
  18. Thread-1:1
  19. Thread-1:2
  20. Thread-0:0
  21. Thread-1:3
  22. Thread-0:1
  23. Thread-0:2
  24. ......
  25. Thread-0:95
  26. Thread-0:96
  27. Thread-0:97
  28. Thread-0:98
  29. Thread-0:99
方式2:實(shí)現(xiàn)Runnable接口 (推薦)

步驟:

自定義類MyuRunnable實(shí)現(xiàn)Runnable接口

重寫run()方法

創(chuàng)建MyRunable類的對象

創(chuàng)建Thread類的對象,并把C步驟的對象作為構(gòu)造參數(shù)傳遞

</>復(fù)制代碼

  1. public class MyRunnable implements Runnable {
  2. public MyRunnable() {
  3. }
  4. @Override
  5. public void run() {
  6. for (int i = 0; i < 100; i++){
  7. //由于實(shí)現(xiàn)接口的方式不能直接使用Thread類的方法了,但是可以間接的使用
  8. System.out.println(Thread.currentThread().getName() + ":" + i);
  9. }
  10. }
  11. }

</>復(fù)制代碼

  1. public class MyRunnableTest {
  2. public static void main(String[] args) {
  3. //創(chuàng)建MyRunnable類的對象
  4. MyRunnable my = new MyRunnable();
  5. //創(chuàng)建Thread類的對象,并把C步驟的對象作為構(gòu)造參數(shù)傳遞
  6. // Thread t1 = new Thread(my);
  7. // Thread t2 = new Thread(my);
  8. //下面具體講解如何設(shè)置線程對象名稱
  9. // t1.setName("User1");
  10. // t1.setName("User2");
  11. Thread t1 = new Thread(my,"User1");
  12. Thread t2 = new Thread(my,"User2");
  13. t1.start()
  14. t2.start();
  15. }
  16. }

實(shí)現(xiàn)接口方式的好處

可以避免由于Java單繼承帶來的局限性

適合多個(gè)相同程序的代碼去處理同一個(gè)資源的情況,把線程同程序的代碼,數(shù)據(jù)有效分離,較好的體現(xiàn)了面向?qū)ο蟮脑O(shè)計(jì)思想

如何理解------可以避免由于Java單繼承帶來的局限性

比如說,某個(gè)類已經(jīng)有父類了,而這個(gè)類想實(shí)現(xiàn)多線程,但是這個(gè)時(shí)候它已經(jīng)不能直接繼承Thread類了

(接口可以多實(shí)現(xiàn)implements,但是繼承extends只能單繼承) ,它的父類也不想繼承Thread因?yàn)椴恍枰獙?shí)現(xiàn)多線程

(三) 獲取和設(shè)置線程對象

</>復(fù)制代碼

  1. //獲取線程的名稱
  2. public?final?String?getName()
  3. //設(shè)置線程的名稱
  4. public?final?void?setName(String?name)
設(shè)置線程的名稱 (如果不設(shè)置名稱的話,默認(rèn)是Thread-??(編號) )

方法一:無參構(gòu)造 + setXxx (推薦)

</>復(fù)制代碼

  1. //創(chuàng)建MyRunnable類的對象
  2. MyRunnable my = new MyRunnable();
  3. //創(chuàng)建Thread類的對象,并把C步驟的對象作為構(gòu)造參數(shù)傳遞
  4. Thread t1 = new Thread(my);
  5. Thread t2 = new Thread(my);
  6. t1.setName("User1");
  7. t1.setName("User2");
  8. //與上面代碼等價(jià)
  9. Thread t1 = new Thread(my,"User1");
  10. Thread t2 = new Thread(my,"User2");

方法二:(稍微麻煩,要手動(dòng)寫MyThread的帶參構(gòu)造方法,方法一不用)

</>復(fù)制代碼

  1. //MyThread類中
  2. public MyThread(String name){
  3. super(name);//直接調(diào)用父類的就好
  4. }
  5. //MyThreadTest類中
  6. MyThread my = new MyThread("admin");
獲取線程名稱

注意:重寫run方法內(nèi)獲取線程名稱的方式

</>復(fù)制代碼

  1. //Thread
  2. getName()
  3. //Runnable
  4. //由于實(shí)現(xiàn)接口的方式不能直接使用Thread類的方法了,但是可以間接的使用
  5. Thread.currentThread().getName()

使用實(shí)現(xiàn)Runnable接口方法的時(shí)候注意:main方法所在的測試類并不繼承Thread類,因此并不能直接使用getName()方法來獲取名稱。

</>復(fù)制代碼

  1. //這種情況Thread類提供了一個(gè)方法:
  2. //public static Thread currentThread():
  3. //返回當(dāng)前正在執(zhí)行的線程對象,返回值是Thread,而Thread恰巧可以調(diào)用getName()方法
  4. System.out.println(Thread.currentThread().getName());
(四) 線程調(diào)度及獲取和設(shè)置線程優(yōu)先級

</>復(fù)制代碼

  1. 假如我們的計(jì)算機(jī)只有一個(gè) CPU,那么 CPU 在某一個(gè)時(shí)刻只能執(zhí)行一條指令,線程只有得到 CPU時(shí)間片,也就是使用權(quán),才可以執(zhí)行指令。那么Java是如何對線程進(jìn)行調(diào)用的呢?

    線程有兩種調(diào)度模型:

  2. 分時(shí)調(diào)度模型 :所有線程輪流使用 CPU 的使用權(quán),平均分配每個(gè)線程占用 CPU 的時(shí)間片

  3. 搶占式調(diào)度模型 :優(yōu)先讓優(yōu)先級高的線程使用 CPU,如果線程的優(yōu)先級相同,那么會隨機(jī)選擇一個(gè),優(yōu)先級高的線程獲取的 CPU 時(shí)間片相對多一些。

Java使用的是搶占式調(diào)度模型

</>復(fù)制代碼

  1. //演示如何設(shè)置和獲取線程優(yōu)先級
  2. //返回線程對象的優(yōu)先級
  3. public final int getPriority()
  4. //更改線程的優(yōu)先級
  5. public final void setPriority(int newPriority)

線程默認(rèn)優(yōu)先級是5。

線程優(yōu)先級的范圍是:1-10。

線程優(yōu)先級高僅僅表示線程獲取的 CPU時(shí)間片的幾率高,但是要在次數(shù)比較多,或者多次運(yùn)行的時(shí)候才能看到比較好的效果。

(五) 線程控制

在后面的案例中會用到一些,這些控制功能不是很難,可以自行測試。

</>復(fù)制代碼

  1. //線程休眠
  2. public static void sleep(long millis)
  3. //線程加入(等待該線程終止,主線程結(jié)束后,其余線程開始搶占資源)
  4. public final void join()
  5. //線程禮讓(暫停當(dāng)前正在執(zhí)行的線程對象,并且執(zhí)行其他線程讓多個(gè)線程的執(zhí)行更加和諧,但是不能保證一人一次)
  6. public static void yield()
  7. //后臺線程(某線程結(jié)束后,其他線程也結(jié)束)
  8. public final void setDaemon(boolean on)
  9. //(過時(shí)了但還可以用)
  10. public final void stop()
  11. //中斷線程
  12. public void interrupt()
(六) 線程的生命周期

新建 —— 創(chuàng)建線程對象

就緒 —— 線程對象已經(jīng)啟動(dòng),但是還沒有獲取到CPU的執(zhí)行權(quán)

運(yùn)行 —— 獲取到了CPU的執(zhí)行權(quán)

阻塞 —— 沒有CPU的執(zhí)權(quán),回到就緒

死亡 —— 代碼運(yùn)行完畢,線程消亡

(七) 多線程電影院出票案例

</>復(fù)制代碼

  1. public class SellTickets implements Runnable {
  2. private int tickets = 100;
  3. @Override
  4. public void run() {
  5. while (true){
  6. if (tickets > 0){
  7. try {
  8. Thread.sleep(100);
  9. } catch (InterruptedException e) {
  10. e.printStackTrace();
  11. }
  12. System.out.println(Thread.currentThread().getName()
  13. + "正在出售第" + (tickets--) + "張票");
  14. }
  15. }
  16. }
  17. }

</>復(fù)制代碼

  1. public class SellTicketsTest {
  2. public static void main(String[] args) {
  3. //創(chuàng)建資源對象
  4. SellTickets st = new SellTickets();
  5. //創(chuàng)建線程對象
  6. Thread t1 = new Thread(st, "窗口1");
  7. Thread t2 = new Thread(st, "窗口2");
  8. Thread t3 = new Thread(st, "窗口3");
  9. //啟動(dòng)線程
  10. t1.start();
  11. t2.start();
  12. t3.start();
  13. }
  14. }

在SellTicket類中添加sleep方法,延遲一下線程,拖慢一下執(zhí)行的速度

通過加入延遲后,就產(chǎn)生了連個(gè)問題:

A:相同的票賣了多次

CPU的一次操作必須是原子性(最簡單的)的 (在讀取tickets--的原來的數(shù)值和減1之后的中間擠進(jìn)了兩個(gè)線程而出現(xiàn)重復(fù))

B:出現(xiàn)了負(fù)數(shù)票

隨機(jī)性和延遲導(dǎo)致的 (三個(gè)線程同時(shí)擠進(jìn)一個(gè)循環(huán)里,tickets--的減法操作有可能在同一個(gè)循環(huán)中被執(zhí)行了多次而出現(xiàn)越界的情況,比如說 tickets要大于0卻越界到了-1)

也就是說,線程1執(zhí)行的同時(shí)線程2也可能在執(zhí)行,而不是線程1執(zhí)行的時(shí)候線程2不能執(zhí)行。

我們先要知道一下哪些問題會導(dǎo)致出問題:

而且這些原因也是以后我們判斷一個(gè)程序是否會有線程安全問題的標(biāo)準(zhǔn)

A:是否是多線程環(huán)境

B:是否有共享數(shù)據(jù)

C:是否有多條語句操作共享數(shù)據(jù)

我們對照起來,我們的程序確實(shí)存在上面的問題,因?yàn)樗鼭M足上面的條件

那我們怎么來解決這個(gè)問題呢?

把多條語句操作共享數(shù)據(jù)的代碼給包成一個(gè)整體,讓某個(gè)線程在執(zhí)行的時(shí)候,別人不能來執(zhí)行

Java給我們提供了:同步機(jī)制

</>復(fù)制代碼

  1. //同步代碼塊:
  2. synchronized(對象){
  3. 需要同步的代碼;
  4. }

同步的好處

同步的出現(xiàn)解決了多線程的安全問題

同步的弊端

當(dāng)線程相當(dāng)多時(shí),因?yàn)槊總€(gè)線程都會去判斷同步上的鎖,這是很耗費(fèi)資源的,無形中會降低程序的運(yùn)行效率

概述:

A:同步代碼塊的鎖對象是誰呢?

任意對象

B:同步方法的格式及鎖對象問題?

把同步關(guān)鍵字加在方法上

同步方法的鎖對象是誰呢?

this

C:靜態(tài)方法及鎖對象問題?

靜態(tài)方法的鎖對象是誰呢?

類的字節(jié)碼文件對象。

我們使用 synchronized 改進(jìn)我們上面的程序,前面線程安全的問題,

</>復(fù)制代碼

  1. public class SellTickets implements Runnable {
  2. private int tickets = 100;
  3. //創(chuàng)建鎖對象
  4. //把這個(gè)關(guān)鍵的鎖對象定義到run()方法(獨(dú)立于線程之外),造成同一把鎖
  5. private Object obj = new Object();
  6. @Override
  7. public void run() {
  8. while (true) {
  9. synchronized (obj) {
  10. if (tickets > 0) {
  11. try {
  12. Thread.sleep(100);
  13. } catch (InterruptedException e) {
  14. e.printStackTrace();
  15. }
  16. System.out.println(Thread.currentThread().getName()
  17. + "正在出售第" + (tickets--) + "張票");
  18. }
  19. }
  20. }
  21. }
  22. }
(八) lock鎖的概述和使用

為了更清晰的表達(dá)如何加鎖和釋放鎖,JDK5以后提供了一個(gè)新的鎖對象Lock

(可以更清晰的看到在哪里加上了鎖,在哪里釋放了鎖,)

</>復(fù)制代碼

  1. void lock() 加鎖
  2. void unlock() 釋放鎖

</>復(fù)制代碼

  1. import java.util.concurrent.locks.Lock;
  2. import java.util.concurrent.locks.ReentrantLock;
  3. public class SellTickets2 implements Runnable {
  4. private int tickets = 100;
  5. private Lock lock = new ReentrantLock();
  6. @Override
  7. public void run() {
  8. while (true) {
  9. try {
  10. lock.lock();
  11. ;
  12. if (tickets > 0) {
  13. try {
  14. Thread.sleep(150);
  15. } catch (InterruptedException e) {
  16. e.printStackTrace();
  17. }
  18. System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "張票");
  19. }
  20. } finally {
  21. lock.unlock();
  22. }
  23. }
  24. }
  25. }
(九) 死鎖問題 (簡單認(rèn)識)

同步弊端

效率低

如果出現(xiàn)了同步嵌套,就容易產(chǎn)生死鎖問題

死鎖問題

是指兩個(gè)或者兩個(gè)以上的線程在執(zhí)行的過程中,因爭奪資源產(chǎn)生的一種互相等待現(xiàn)象

(十) 等待喚醒機(jī)制

我們前面假定的電影院場景,其實(shí)還是有一定局限的,我們所假定的票數(shù)是一定的,但是實(shí)際生活中,往往是一種供需共存的狀態(tài),例如去買早點(diǎn),當(dāng)消費(fèi)者買走一些后,而作為生產(chǎn)者的店家就會補(bǔ)充一些商品,為了研究這一種場景,我們所要學(xué)習(xí)的就是Java的等待喚醒機(jī)制

</>復(fù)制代碼

  1. 生產(chǎn)者消費(fèi)者問題(英語:Producer-consumer problem),也稱有限緩沖問題(英語:Bounded-buffer problem),是一個(gè)多進(jìn)程同步問題的經(jīng)典案例。該問題描述了共享固定大小緩沖區(qū)的兩個(gè)進(jìn)程——即所謂的“生產(chǎn)者”和“消費(fèi)者”——在實(shí)際運(yùn)行時(shí)會發(fā)生的問題。生產(chǎn)者的主要作用是生成一定量的數(shù)據(jù)放到緩沖區(qū)中,然后重復(fù)此過程。與此同時(shí),消費(fèi)者也在緩沖區(qū)消耗這些數(shù)據(jù)。該問題的關(guān)鍵就是要保證生產(chǎn)者不會在緩沖區(qū)滿時(shí)加入數(shù)據(jù),消費(fèi)者也不會在緩沖區(qū)中空時(shí)消耗數(shù)據(jù)。

我們用通俗一點(diǎn)的話來解釋一下這個(gè)問題

Java使用的是搶占式調(diào)度模型

A:如果消費(fèi)者先搶到了CPU的執(zhí)行權(quán),它就會去消費(fèi)數(shù)據(jù),但是現(xiàn)在的數(shù)據(jù)是默認(rèn)值,如果沒有意義,應(yīng)該等數(shù)據(jù)有意義再消費(fèi)。就好比買家進(jìn)了店鋪早點(diǎn)卻還沒有做出來,只能等早點(diǎn)做出來了再消費(fèi)

B:如果生產(chǎn)者先搶到CPU的執(zhí)行權(quán),它就回去生產(chǎn)數(shù)據(jù),但是,當(dāng)它產(chǎn)生完數(shù)據(jù)后,還繼續(xù)擁有執(zhí)行權(quán),它還能繼續(xù)產(chǎn)生數(shù)據(jù),這是不合理的,你應(yīng)該等待消費(fèi)者將數(shù)據(jù)消費(fèi)掉,再進(jìn)行生產(chǎn)。 這又好比,店鋪不能無止境的做早點(diǎn),賣一些,再做,避免虧本

梳理思路

A:生產(chǎn)者 —— 先看是否有數(shù)據(jù),有就等待,沒有就生產(chǎn),生產(chǎn)完之后通知消費(fèi)者來消費(fèi)數(shù)據(jù)

B:消費(fèi)者 —— 先看是否有數(shù)據(jù),有就消費(fèi),沒有就等待,通知生產(chǎn)者生產(chǎn)數(shù)據(jù)

解釋喚醒——讓線程池中的線程具備執(zhí)行資格

Object類提供了三個(gè)方法:

</>復(fù)制代碼

  1. //等待
  2. wait()
  3. //喚醒單個(gè)線程
  4. notify()
  5. //喚醒所有線程
  6. notifyAll()

注意:這三個(gè)方法都必須在同步代碼塊中執(zhí)行 (例如synchronized塊),同時(shí)在使用時(shí)必須標(biāo)明所屬鎖,這樣才可以得出這些方法操作的到底是哪個(gè)鎖上的線程

為什么這些方法不定義在Thread類中呢 ?

這些方法的調(diào)用必須通過鎖對象調(diào)用,而我們剛才使用的鎖對象是任意鎖對象。

所以,這些方法必須定義在Object類中。

我們來寫一段簡單的代碼實(shí)現(xiàn)等待喚醒機(jī)制

</>復(fù)制代碼

  1. public class Student {
  2. String name;
  3. int age;
  4. boolean flag;// 默認(rèn)情況是沒有數(shù)據(jù)(false),如果是true,說明有數(shù)據(jù)
  5. public Student() {
  6. }
  7. }

</>復(fù)制代碼

  1. public class SetThread implements Runnable {
  2. private Student s;
  3. private int x = 0;
  4. public SetThread(Student s) {
  5. this.s = s;
  6. }
  7. @Override
  8. public void run() {
  9. while (true){
  10. synchronized (s) {
  11. //判斷有沒有數(shù)據(jù)
  12. //如果有數(shù)據(jù),就wait
  13. if (s.flag) {
  14. try {
  15. s.wait(); //t1等待,釋放鎖
  16. } catch (InterruptedException e) {
  17. e.printStackTrace();
  18. }
  19. }
  20. //沒有數(shù)據(jù),就生產(chǎn)數(shù)據(jù)
  21. if (x % 2 == 0) {
  22. s.name = "admin";
  23. s.age = 20;
  24. } else {
  25. s.name = "User";
  26. s.age = 30;
  27. }
  28. x++;
  29. //現(xiàn)在數(shù)據(jù)就已經(jīng)存在了,修改標(biāo)記
  30. s.flag = true;
  31. //喚醒線程
  32. //喚醒t2,喚醒并不表示你立馬可以執(zhí)行,必須還得搶CPU的執(zhí)行權(quán)。
  33. s.notify();
  34. }
  35. }
  36. }
  37. }

</>復(fù)制代碼

  1. package cn.bwh_05_Notify;
  2. public class GetThread implements Runnable {
  3. private Student s;
  4. public GetThread(Student s) {
  5. this.s = s;
  6. }
  7. @Override
  8. public void run() {
  9. while (true){
  10. synchronized (s){
  11. //如果沒有數(shù)據(jù),就等待
  12. if (!s.flag){
  13. try {
  14. s.wait();
  15. } catch (InterruptedException e) {
  16. e.printStackTrace();
  17. }
  18. }
  19. System.out.println(s.name + "---" + s.age);
  20. //修改標(biāo)記
  21. s.flag = false;
  22. //喚醒線程t1
  23. s.notify();
  24. }
  25. }
  26. }
  27. }

</>復(fù)制代碼

  1. package cn.bwh_05_Notify;
  2. public class StudentTest {
  3. public static void main(String[] args) {
  4. Student s = new Student();
  5. //設(shè)置和獲取的類
  6. SetThread st = new SetThread(s);
  7. GetThread gt = new GetThread(s);
  8. //線程類
  9. Thread t1 = new Thread(st);
  10. Thread t2 = new Thread(gt);
  11. //啟動(dòng)線程
  12. t1.start();
  13. t2.start();
  14. }
  15. }
  16. //運(yùn)行結(jié)果依次交替出現(xiàn)

生產(chǎn)者消費(fèi)者之等待喚醒機(jī)制代碼優(yōu)化

最終版代碼(在Student類中有大改動(dòng),然后GetThread類和SetThread類簡潔很多)

</>復(fù)制代碼

  1. public class Student {
  2. private String name;
  3. private int age;
  4. private boolean flag;
  5. public synchronized void set(String name, int age) {
  6. if (this.flag) {
  7. try {
  8. this.wait();
  9. } catch (InterruptedException e) {
  10. e.printStackTrace();
  11. }
  12. }
  13. this.name = name;
  14. this.age = age;
  15. this.flag = true;
  16. this.notify();
  17. }
  18. public synchronized void get() {
  19. if (!this.flag) {
  20. try {
  21. this.wait();
  22. } catch (InterruptedException e) {
  23. e.printStackTrace();
  24. }
  25. }
  26. System.out.println(this.name + "---" + this.age);
  27. this.flag = false;
  28. this.notify();
  29. }
  30. }

</>復(fù)制代碼

  1. public class SetThread implements Runnable {
  2. private Student s;
  3. private int x = 0;
  4. public SetThread(Student s) {
  5. this.s = s;
  6. }
  7. @Override
  8. public void run() {
  9. while (true) {
  10. if (x % 2 == 0) {
  11. s.set("admin", 20);
  12. } else {
  13. s.set("User", 30);
  14. }
  15. x++;
  16. }
  17. }
  18. }

</>復(fù)制代碼

  1. public class GetThread implements Runnable{
  2. private Student s;
  3. public GetThread(Student s) {
  4. this.s = s;
  5. }
  6. @Override
  7. public void run() {
  8. while (true){
  9. s.get();
  10. }
  11. }
  12. }

</>復(fù)制代碼

  1. public class StudentTest {
  2. public static void main(String[] args) {
  3. Student s = new Student();
  4. //設(shè)置和獲取的類
  5. SetThread st = new SetThread(s);
  6. GetThread gt = new GetThread(s);
  7. Thread t1 = new Thread(st);
  8. Thread t2 = new Thread(gt);
  9. t1.start();
  10. t2.start();
  11. }
  12. }

最終版代碼特點(diǎn):

把Student的成員變量給私有的了。

把設(shè)置和獲取的操作給封裝成了功能,并加了同步。

設(shè)置或者獲取的線程里面只需要調(diào)用方法即可

(十一) 線程池

程序啟動(dòng)一個(gè)新線程成本是比較高的,因?yàn)樗婕暗揭c操作系統(tǒng)進(jìn)行交互。而使用線程池可以很好的提高性能,尤其是當(dāng)程序中要?jiǎng)?chuàng)建大量生存期很短的線程時(shí),更應(yīng)該考慮使用線程池

線程池里的每一個(gè)線程代碼結(jié)束后,并不會死亡,而是再次回到線程池中成為空閑狀態(tài),等待下一個(gè)對象來使用

在JDK5之前,我們必須手動(dòng)實(shí)現(xiàn)自己的線程池,從JDK5開始,Java內(nèi)置支持線程池

</>復(fù)制代碼

  1. JDK5新增了一個(gè)Executors工廠類來產(chǎn)生線程池,有如下幾個(gè)方法
  2. //創(chuàng)建一個(gè)具有緩存功能的線程池
  3. //緩存:百度瀏覽過的信息再次訪問
  4. public static?ExecutorService newCachedThreadPool()
  5. //創(chuàng)建一個(gè)可重用的,具有固定線程數(shù)的線程池
  6. public static?ExecutorService newFixedThreadPool(intnThreads)
  7. ??
  8. //創(chuàng)建一個(gè)只有單線程的線程池,相當(dāng)于上個(gè)方法的參數(shù)是1?
  9. public static?ExecutorService newSingleThreadExecutor()
  10. ??
  11. 這些方法的返回值是ExecutorService對象,該對象表示一個(gè)線程池,可以執(zhí)行Runnable對象或者Callable對象代表的線程。它提供了如下方法
  12. Future submit(Runnable task)
  13. Future submit(Callable task)

</>復(fù)制代碼

  1. import java.util.concurrent.ExecutorService;
  2. import java.util.concurrent.Executors;
  3. public class ExecutorDemo {
  4. public static void main(String[] args) {
  5. //創(chuàng)建一個(gè)線程池對象,控制要?jiǎng)?chuàng)建幾個(gè)線程對象
  6. ExecutorService pool = Executors.newFixedThreadPool(2);
  7. //可以執(zhí)行Runnalble對象或者Callable對象代表的線程
  8. pool.submit(new MyRunnable());
  9. pool.submit(new MyRunnable());
  10. //結(jié)束線程池
  11. pool.shutdown();
  12. }
  13. }
(十二) 匿名內(nèi)部類的方式實(shí)現(xiàn)多線程程序

匿名內(nèi)部類的格式:

</>復(fù)制代碼

  1. new 類名或者接口名( ) {
  2. 重寫方法;
  3. };

本質(zhì):是該類或者接口的子類對象

</>復(fù)制代碼

  1. public class ThreadDemo {
  2. public static void main(String[] args) {
  3. new Thread() {
  4. @Override
  5. public void run() {
  6. for (int i = 0; i < 100; i++) {
  7. System.out.println(Thread.currentThread().getName() + i);
  8. }
  9. }
  10. }.start();
  11. }
  12. }

</>復(fù)制代碼

  1. public class RunnableDemo {
  2. public static void main(String[] args) {
  3. new Thread(new Runnable() {
  4. @Override
  5. public void run() {
  6. for (int i = 0; i < 100; i++) {
  7. System.out.println(Thread.currentThread().getName() + i);
  8. }
  9. }
  10. }).start();
  11. }
  12. }
(十三) 定時(shí)器

定時(shí)器是一個(gè)應(yīng)用十分廣泛的線程工具,可用于調(diào)度多個(gè)定時(shí)任務(wù)以后臺線程的方式執(zhí)行。在Java中,可以通過Timer和TimerTask類來實(shí)現(xiàn)定義調(diào)度的功能

Timer

</>復(fù)制代碼

  1. ·public Timer()
  2. public void schedule(TimerTask task, long delay)
  3. public void schedule(TimerTask task,long delay,long period)

TimerTask

</>復(fù)制代碼

  1. abstract void run()
  2. public boolean cancel()

開發(fā)中

Quartz是一個(gè)完全由java編寫的開源調(diào)度框架

結(jié)尾:

如果內(nèi)容中有什么不足,或者錯(cuò)誤的地方,歡迎大家給我留言提出意見, 蟹蟹大家 !^_^

如果能幫到你的話,那就來關(guān)注我吧!(系列文章均會在公眾號第一時(shí)間更新)

</>復(fù)制代碼

  1. 在這里的我們素不相識,卻都在為了自己的夢而努力 ?

    一個(gè)堅(jiān)持推送原創(chuàng)Java技術(shù)的公眾號:理想二旬不止

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/75448.html

相關(guān)文章

  • JAVA 線程和并發(fā)基礎(chǔ)

    摘要:線程可以被稱為輕量級進(jìn)程。一個(gè)守護(hù)線程是在后臺執(zhí)行并且不會阻止終止的線程。其他的線程狀態(tài)還有,和。上下文切換是多任務(wù)操作系統(tǒng)和多線程環(huán)境的基本特征。在的線程中并沒有可供任何對象使用的鎖和同步器。 原文:Java Multi-Threading and Concurrency Interview Questions with Answers 翻譯:并發(fā)編程網(wǎng) - 鄭旭東 校對:方騰飛 多...

    vboy1010 評論0 收藏0
  • JAVA 線程和并發(fā)基礎(chǔ)面試問答

    摘要:多線程和并發(fā)問題是技術(shù)面試中面試官比較喜歡問的問題之一。線程可以被稱為輕量級進(jìn)程。一個(gè)守護(hù)線程是在后臺執(zhí)行并且不會阻止終止的線程。其他的線程狀態(tài)還有,和。上下文切換是多任務(wù)操作系統(tǒng)和多線程環(huán)境的基本特征。 多線程和并發(fā)問題是 Java 技術(shù)面試中面試官比較喜歡問的問題之一。在這里,從面試的角度列出了大部分重要的問題,但是你仍然應(yīng)該牢固的掌握J(rèn)ava多線程基礎(chǔ)知識來對應(yīng)日后碰到的問題。(...

    dreamans 評論0 收藏0
  • 40道阿里巴巴JAVA研發(fā)崗線程面試題詳解,你能答出

    摘要:但是單核我們還是要應(yīng)用多線程,就是為了防止阻塞。多線程可以防止這個(gè)問題,多條線程同時(shí)運(yùn)行,哪怕一條線程的代碼執(zhí)行讀取數(shù)據(jù)阻塞,也不會影響其它任務(wù)的執(zhí)行。 1、多線程有什么用?一個(gè)可能在很多人看來很扯淡的一個(gè)問題:我會用多線程就好了,還管它有什么用?在我看來,這個(gè)回答更扯淡。所謂知其然知其所以然,會用只是知其然,為什么用才是知其所以然,只有達(dá)到知其然知其所以然的程度才可以說是把一個(gè)知識點(diǎn)...

    lpjustdoit 評論0 收藏0
  • 想進(jìn)大廠?50個(gè)線程面試題,你會少?【后25題】(二)

    摘要:大多數(shù)待遇豐厚的開發(fā)職位都要求開發(fā)者精通多線程技術(shù)并且有豐富的程序開發(fā)調(diào)試優(yōu)化經(jīng)驗(yàn),所以線程相關(guān)的問題在面試中經(jīng)常會被提到。掌握了這些技巧,你就可以輕松應(yīng)對多線程和并發(fā)面試了。進(jìn)入等待通行準(zhǔn)許時(shí),所提供的對象。 最近看到網(wǎng)上流傳著,各種面試經(jīng)驗(yàn)及面試題,往往都是一大堆技術(shù)題目貼上去,而沒有答案。 不管你是新程序員還是老手,你一定在面試中遇到過有關(guān)線程的問題。Java語言一個(gè)重要的特點(diǎn)就...

    caozhijian 評論0 收藏0
  • 超詳細(xì)的Java面試題總結(jié)(二)之Java基礎(chǔ)知識篇

    摘要:超詳細(xì)的面試題總結(jié)一之基本知識多線程和虛擬機(jī)創(chuàng)建線程有幾種不同的方式你喜歡哪一種為什么繼承類實(shí)現(xiàn)接口應(yīng)用程序可以使用框架來創(chuàng)建線程池實(shí)現(xiàn)接口。死亡線程方法執(zhí)行結(jié)束,或者因異常退出了方法,則該線程結(jié)束生命周期。死亡的線程不可再次復(fù)生。 超詳細(xì)的Java面試題總結(jié)(一)之Java基本知識 多線程和Java虛擬機(jī) 創(chuàng)建線程有幾種不同的方式?你喜歡哪一種?為什么? 繼承Thread類 實(shí)現(xiàn)R...

    wangjuntytl 評論0 收藏0
  • 想進(jìn)大廠?50個(gè)線程面試題,你會少?(一)

    摘要:下面是線程相關(guān)的熱門面試題,你可以用它來好好準(zhǔn)備面試。線程安全問題都是由全局變量及靜態(tài)變量引起的。持有自旋鎖的線程在之前應(yīng)該釋放自旋鎖以便其它線程可以獲得自旋鎖。 最近看到網(wǎng)上流傳著,各種面試經(jīng)驗(yàn)及面試題,往往都是一大堆技術(shù)題目貼上去,而沒有答案。 不管你是新程序員還是老手,你一定在面試中遇到過有關(guān)線程的問題。Java語言一個(gè)重要的特點(diǎn)就是內(nèi)置了對并發(fā)的支持,讓Java大受企業(yè)和程序員...

    wow_worktile 評論0 收藏0

發(fā)表評論

0條評論

高璐

|高級講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<