摘要:是不能直接調用系統(tǒng)功能的,所以,我們沒有辦法直接實現(xiàn)多線程程序。通過查看,我們知道了有種方式實現(xiàn)多線程程序。使用的是搶占式調度模型演示如何設置和獲取線程優(yōu)先級返回線程對象的優(yōu)先級更改線程的優(yōu)先級線程默認優(yōu)先級是。線程優(yōu)先級的范圍是。
第五階段 多線程 前言:
一個場景:周末,帶著并不存在的女票去看電影,無論是現(xiàn)場買票也好,又或是手機買票也好,上一秒還有位置,遲鈍了一下以后,就顯示該座位已經無法選中,一不留神就沒有座位了,影院的票是一定的,但是究竟是如何做到,多個窗口或者用戶同時出票而又不重復的呢? 這就是我們今天所要講解的多線程問題(一) 線程和進程的概述 (1) 進程
進程:進程是系統(tǒng)進行資源分配和調用的獨立單位。每一個進程都有它自己的內存空間和系統(tǒng)資源
多線程:在同一個時間段內可以執(zhí)行多個任務,提高了CPU的使用率
(2) 線程線程:進程的執(zhí)行單元,執(zhí)行路徑
單線程:一個應用程序只有一條執(zhí)行路徑
多線程:一個應用程序有多條執(zhí)行路徑
多進程的意義?—— 提高CPU的使用率
多線程的意義? —— 提高應用程序的使用率
(3) 補充并行和并發(fā)
并行是物理上同時發(fā)生,指在某一個時間點同時運行多個程序
并發(fā)是邏輯上同時發(fā)生,指在某一個時間段內同時運行多個程序
Java程序運行原理和JVM的啟動是否是多線程的 ?
Java程序的運行原理:
由java命令啟動JVM,JVM啟動就相當于啟動了一個進程
接著有該進程創(chuàng)建了一個主線程去調用main方法
JVM虛擬機的啟動是單線程的還是多線程的 ?
垃圾回收線程也要先啟動,否則很容易會出現(xiàn)內存溢出
現(xiàn)在的垃圾回收線程加上前面的主線程,最低啟動了兩個線程,所以,jvm的啟動其實是多線程的
JVM啟動至少啟動了垃圾回收線程和主線程,所以是多線程的
(二) 多線程代碼實現(xiàn)需求:我們要實現(xiàn)多線程的程序。
如何實現(xiàn)呢?
由于線程是依賴進程而存在的,所以我們應該先創(chuàng)建一個進程出來。
而進程是由系統(tǒng)創(chuàng)建的,所以我們應該去調用系統(tǒng)功能創(chuàng)建一個進程。
Java是不能直接調用系統(tǒng)功能的,所以,我們沒有辦法直接實現(xiàn)多線程程序。
但是呢?Java可以去調用C/C++寫好的程序來實現(xiàn)多線程程序。
由C/C++去調用系統(tǒng)功能創(chuàng)建進程,然后由Java去調用這樣的東西,
然后提供一些類供我們使用。我們就可以實現(xiàn)多線程程序了。
通過查看API,我們知道了有2種方式實現(xiàn)多線程程序。
方式1:繼承Thread類步驟:
自定義MyThread(自定義類名)繼承Thread類
MyThread類中重寫run()
創(chuàng)建對象
啟動線程
public class MyThread extends Thread{ public MyThread() { } @Override public void run() { for (int i = 0; i < 100; i++){ System.out.println(getName() + ":" + i); } } }
public class MyThreadTest { public static void main(String[] args) { //創(chuàng)建線程對象 MyThread my = new MyThread(); //啟動線程,run()相當于普通方法的調用,單線程效果 //my.run(); //首先啟動了線程,然后再由jvm調用該線程的run()方法,多線程效果 my.start(); //兩個線程演示,多線程效果需要創(chuàng)建多個對象而不是一個對象多次調用start()方法 MyThread my1 = new MyThread(); MyThread my2 = new MyThread(); my1.start(); my2.start(); } } //運行結果 Thread-1:0 Thread-1:1 Thread-1:2 Thread-0:0 Thread-1:3 Thread-0:1 Thread-0:2 ...... Thread-0:95 Thread-0:96 Thread-0:97 Thread-0:98 Thread-0:99方式2:實現(xiàn)Runnable接口 (推薦)
步驟:
自定義類MyuRunnable實現(xiàn)Runnable接口
重寫run()方法
創(chuàng)建MyRunable類的對象
創(chuàng)建Thread類的對象,并把C步驟的對象作為構造參數傳遞
public class MyRunnable implements Runnable { public MyRunnable() { } @Override public void run() { for (int i = 0; i < 100; i++){ //由于實現(xiàn)接口的方式不能直接使用Thread類的方法了,但是可以間接的使用 System.out.println(Thread.currentThread().getName() + ":" + i); } } }
public class MyRunnableTest { public static void main(String[] args) { //創(chuàng)建MyRunnable類的對象 MyRunnable my = new MyRunnable(); //創(chuàng)建Thread類的對象,并把C步驟的對象作為構造參數傳遞 // Thread t1 = new Thread(my); // Thread t2 = new Thread(my); //下面具體講解如何設置線程對象名稱 // t1.setName("User1"); // t1.setName("User2"); Thread t1 = new Thread(my,"User1"); Thread t2 = new Thread(my,"User2"); t1.start() t2.start(); } }
實現(xiàn)接口方式的好處
可以避免由于Java單繼承帶來的局限性
適合多個相同程序的代碼去處理同一個資源的情況,把線程同程序的代碼,數據有效分離,較好的體現(xiàn)了面向對象的設計思想
如何理解------可以避免由于Java單繼承帶來的局限性
比如說,某個類已經有父類了,而這個類想實現(xiàn)多線程,但是這個時候它已經不能直接繼承Thread類了
(接口可以多實現(xiàn)implements,但是繼承extends只能單繼承) ,它的父類也不想繼承Thread因為不需要實現(xiàn)多線程
(三) 獲取和設置線程對象//獲取線程的名稱 public?final?String?getName() //設置線程的名稱 public?final?void?setName(String?name)設置線程的名稱 (如果不設置名稱的話,默認是Thread-??(編號) )
方法一:無參構造 + setXxx (推薦)
//創(chuàng)建MyRunnable類的對象 MyRunnable my = new MyRunnable(); //創(chuàng)建Thread類的對象,并把C步驟的對象作為構造參數傳遞 Thread t1 = new Thread(my); Thread t2 = new Thread(my); t1.setName("User1"); t1.setName("User2"); //與上面代碼等價 Thread t1 = new Thread(my,"User1"); Thread t2 = new Thread(my,"User2");
方法二:(稍微麻煩,要手動寫MyThread的帶參構造方法,方法一不用)
//MyThread類中 public MyThread(String name){ super(name);//直接調用父類的就好 } //MyThreadTest類中 MyThread my = new MyThread("admin");獲取線程名稱
注意:重寫run方法內獲取線程名稱的方式
//Thread getName() //Runnable //由于實現(xiàn)接口的方式不能直接使用Thread類的方法了,但是可以間接的使用 Thread.currentThread().getName()
使用實現(xiàn)Runnable接口方法的時候注意:main方法所在的測試類并不繼承Thread類,因此并不能直接使用getName()方法來獲取名稱。
//這種情況Thread類提供了一個方法: //public static Thread currentThread(): //返回當前正在執(zhí)行的線程對象,返回值是Thread,而Thread恰巧可以調用getName()方法 System.out.println(Thread.currentThread().getName());(四) 線程調度及獲取和設置線程優(yōu)先級
假如我們的計算機只有一個 CPU,那么 CPU 在某一個時刻只能執(zhí)行一條指令,線程只有得到 CPU時間片,也就是使用權,才可以執(zhí)行指令。那么Java是如何對線程進行調用的呢?線程有兩種調度模型:
分時調度模型 :所有線程輪流使用 CPU 的使用權,平均分配每個線程占用 CPU 的時間片
搶占式調度模型 :優(yōu)先讓優(yōu)先級高的線程使用 CPU,如果線程的優(yōu)先級相同,那么會隨機選擇一個,優(yōu)先級高的線程獲取的 CPU 時間片相對多一些。
Java使用的是搶占式調度模型
//演示如何設置和獲取線程優(yōu)先級 //返回線程對象的優(yōu)先級 public final int getPriority() //更改線程的優(yōu)先級 public final void setPriority(int newPriority)
線程默認優(yōu)先級是5。
線程優(yōu)先級的范圍是:1-10。
線程優(yōu)先級高僅僅表示線程獲取的 CPU時間片的幾率高,但是要在次數比較多,或者多次運行的時候才能看到比較好的效果。
(五) 線程控制在后面的案例中會用到一些,這些控制功能不是很難,可以自行測試。
//線程休眠 public static void sleep(long millis) //線程加入(等待該線程終止,主線程結束后,其余線程開始搶占資源) public final void join() //線程禮讓(暫停當前正在執(zhí)行的線程對象,并且執(zhí)行其他線程讓多個線程的執(zhí)行更加和諧,但是不能保證一人一次) public static void yield() //后臺線程(某線程結束后,其他線程也結束) public final void setDaemon(boolean on) //(過時了但還可以用) public final void stop() //中斷線程 public void interrupt()(六) 線程的生命周期
新建 —— 創(chuàng)建線程對象
就緒 —— 線程對象已經啟動,但是還沒有獲取到CPU的執(zhí)行權
運行 —— 獲取到了CPU的執(zhí)行權
阻塞 —— 沒有CPU的執(zhí)權,回到就緒
死亡 —— 代碼運行完畢,線程消亡
(七) 多線程電影院出票案例public class SellTickets implements Runnable { private int tickets = 100; @Override public void run() { while (true){ if (tickets > 0){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "張票"); } } } }
public class SellTicketsTest { public static void main(String[] args) { //創(chuàng)建資源對象 SellTickets st = new SellTickets(); //創(chuàng)建線程對象 Thread t1 = new Thread(st, "窗口1"); Thread t2 = new Thread(st, "窗口2"); Thread t3 = new Thread(st, "窗口3"); //啟動線程 t1.start(); t2.start(); t3.start(); } }
在SellTicket類中添加sleep方法,延遲一下線程,拖慢一下執(zhí)行的速度
通過加入延遲后,就產生了連個問題:
A:相同的票賣了多次
CPU的一次操作必須是原子性(最簡單的)的 (在讀取tickets--的原來的數值和減1之后的中間擠進了兩個線程而出現(xiàn)重復)
B:出現(xiàn)了負數票
隨機性和延遲導致的 (三個線程同時擠進一個循環(huán)里,tickets--的減法操作有可能在同一個循環(huán)中被執(zhí)行了多次而出現(xiàn)越界的情況,比如說 tickets要大于0卻越界到了-1)
也就是說,線程1執(zhí)行的同時線程2也可能在執(zhí)行,而不是線程1執(zhí)行的時候線程2不能執(zhí)行。
我們先要知道一下哪些問題會導致出問題:
而且這些原因也是以后我們判斷一個程序是否會有線程安全問題的標準
A:是否是多線程環(huán)境
B:是否有共享數據
C:是否有多條語句操作共享數據
我們對照起來,我們的程序確實存在上面的問題,因為它滿足上面的條件
那我們怎么來解決這個問題呢?
把多條語句操作共享數據的代碼給包成一個整體,讓某個線程在執(zhí)行的時候,別人不能來執(zhí)行
Java給我們提供了:同步機制
//同步代碼塊: synchronized(對象){ 需要同步的代碼; }
同步的好處
同步的出現(xiàn)解決了多線程的安全問題
同步的弊端
當線程相當多時,因為每個線程都會去判斷同步上的鎖,這是很耗費資源的,無形中會降低程序的運行效率
概述:
A:同步代碼塊的鎖對象是誰呢?
任意對象
B:同步方法的格式及鎖對象問題?
把同步關鍵字加在方法上
同步方法的鎖對象是誰呢?
this
C:靜態(tài)方法及鎖對象問題?
靜態(tài)方法的鎖對象是誰呢?
類的字節(jié)碼文件對象。
我們使用 synchronized 改進我們上面的程序,前面線程安全的問題,
public class SellTickets implements Runnable { private int tickets = 100; //創(chuàng)建鎖對象 //把這個關鍵的鎖對象定義到run()方法(獨立于線程之外),造成同一把鎖 private Object obj = new Object(); @Override public void run() { while (true) { synchronized (obj) { if (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "張票"); } } } } }(八) lock鎖的概述和使用
為了更清晰的表達如何加鎖和釋放鎖,JDK5以后提供了一個新的鎖對象Lock
(可以更清晰的看到在哪里加上了鎖,在哪里釋放了鎖,)
void lock() 加鎖 void unlock() 釋放鎖
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class SellTickets2 implements Runnable { private int tickets = 100; private Lock lock = new ReentrantLock(); @Override public void run() { while (true) { try { lock.lock(); ; if (tickets > 0) { try { Thread.sleep(150); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "張票"); } } finally { lock.unlock(); } } } }(九) 死鎖問題 (簡單認識)
同步弊端
效率低
如果出現(xiàn)了同步嵌套,就容易產生死鎖問題
死鎖問題
是指兩個或者兩個以上的線程在執(zhí)行的過程中,因爭奪資源產生的一種互相等待現(xiàn)象
(十) 等待喚醒機制我們前面假定的電影院場景,其實還是有一定局限的,我們所假定的票數是一定的,但是實際生活中,往往是一種供需共存的狀態(tài),例如去買早點,當消費者買走一些后,而作為生產者的店家就會補充一些商品,為了研究這一種場景,我們所要學習的就是Java的等待喚醒機制
生產者消費者問題(英語:Producer-consumer problem),也稱有限緩沖問題(英語:Bounded-buffer problem),是一個多進程同步問題的經典案例。該問題描述了共享固定大小緩沖區(qū)的兩個進程——即所謂的“生產者”和“消費者”——在實際運行時會發(fā)生的問題。生產者的主要作用是生成一定量的數據放到緩沖區(qū)中,然后重復此過程。與此同時,消費者也在緩沖區(qū)消耗這些數據。該問題的關鍵就是要保證生產者不會在緩沖區(qū)滿時加入數據,消費者也不會在緩沖區(qū)中空時消耗數據。
我們用通俗一點的話來解釋一下這個問題
Java使用的是搶占式調度模型
A:如果消費者先搶到了CPU的執(zhí)行權,它就會去消費數據,但是現(xiàn)在的數據是默認值,如果沒有意義,應該等數據有意義再消費。就好比買家進了店鋪早點卻還沒有做出來,只能等早點做出來了再消費
B:如果生產者先搶到CPU的執(zhí)行權,它就回去生產數據,但是,當它產生完數據后,還繼續(xù)擁有執(zhí)行權,它還能繼續(xù)產生數據,這是不合理的,你應該等待消費者將數據消費掉,再進行生產。 這又好比,店鋪不能無止境的做早點,賣一些,再做,避免虧本
梳理思路:
A:生產者 —— 先看是否有數據,有就等待,沒有就生產,生產完之后通知消費者來消費數據
B:消費者 —— 先看是否有數據,有就消費,沒有就等待,通知生產者生產數據
解釋:喚醒——讓線程池中的線程具備執(zhí)行資格
Object類提供了三個方法:
//等待 wait() //喚醒單個線程 notify() //喚醒所有線程 notifyAll()
注意:這三個方法都必須在同步代碼塊中執(zhí)行 (例如synchronized塊),同時在使用時必須標明所屬鎖,這樣才可以得出這些方法操作的到底是哪個鎖上的線程
為什么這些方法不定義在Thread類中呢 ?
這些方法的調用必須通過鎖對象調用,而我們剛才使用的鎖對象是任意鎖對象。
所以,這些方法必須定義在Object類中。
我們來寫一段簡單的代碼實現(xiàn)等待喚醒機制
public class Student { String name; int age; boolean flag;// 默認情況是沒有數據(false),如果是true,說明有數據 public Student() { } }
public class SetThread implements Runnable { private Student s; private int x = 0; public SetThread(Student s) { this.s = s; } @Override public void run() { while (true){ synchronized (s) { //判斷有沒有數據 //如果有數據,就wait if (s.flag) { try { s.wait(); //t1等待,釋放鎖 } catch (InterruptedException e) { e.printStackTrace(); } } //沒有數據,就生產數據 if (x % 2 == 0) { s.name = "admin"; s.age = 20; } else { s.name = "User"; s.age = 30; } x++; //現(xiàn)在數據就已經存在了,修改標記 s.flag = true; //喚醒線程 //喚醒t2,喚醒并不表示你立馬可以執(zhí)行,必須還得搶CPU的執(zhí)行權。 s.notify(); } } } }
package cn.bwh_05_Notify; public class GetThread implements Runnable { private Student s; public GetThread(Student s) { this.s = s; } @Override public void run() { while (true){ synchronized (s){ //如果沒有數據,就等待 if (!s.flag){ try { s.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(s.name + "---" + s.age); //修改標記 s.flag = false; //喚醒線程t1 s.notify(); } } } }
package cn.bwh_05_Notify; public class StudentTest { public static void main(String[] args) { Student s = new Student(); //設置和獲取的類 SetThread st = new SetThread(s); GetThread gt = new GetThread(s); //線程類 Thread t1 = new Thread(st); Thread t2 = new Thread(gt); //啟動線程 t1.start(); t2.start(); } } //運行結果依次交替出現(xiàn)
生產者消費者之等待喚醒機制代碼優(yōu)化
最終版代碼(在Student類中有大改動,然后GetThread類和SetThread類簡潔很多)
public class Student { private String name; private int age; private boolean flag; public synchronized void set(String name, int age) { if (this.flag) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } this.name = name; this.age = age; this.flag = true; this.notify(); } public synchronized void get() { if (!this.flag) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(this.name + "---" + this.age); this.flag = false; this.notify(); } }
public class SetThread implements Runnable { private Student s; private int x = 0; public SetThread(Student s) { this.s = s; } @Override public void run() { while (true) { if (x % 2 == 0) { s.set("admin", 20); } else { s.set("User", 30); } x++; } } }
public class GetThread implements Runnable{ private Student s; public GetThread(Student s) { this.s = s; } @Override public void run() { while (true){ s.get(); } } }
public class StudentTest { public static void main(String[] args) { Student s = new Student(); //設置和獲取的類 SetThread st = new SetThread(s); GetThread gt = new GetThread(s); Thread t1 = new Thread(st); Thread t2 = new Thread(gt); t1.start(); t2.start(); } }
最終版代碼特點:
把Student的成員變量給私有的了。
把設置和獲取的操作給封裝成了功能,并加了同步。
設置或者獲取的線程里面只需要調用方法即可
(十一) 線程池程序啟動一個新線程成本是比較高的,因為它涉及到要與操作系統(tǒng)進行交互。而使用線程池可以很好的提高性能,尤其是當程序中要創(chuàng)建大量生存期很短的線程時,更應該考慮使用線程池
線程池里的每一個線程代碼結束后,并不會死亡,而是再次回到線程池中成為空閑狀態(tài),等待下一個對象來使用
在JDK5之前,我們必須手動實現(xiàn)自己的線程池,從JDK5開始,Java內置支持線程池
JDK5新增了一個Executors工廠類來產生線程池,有如下幾個方法 //創(chuàng)建一個具有緩存功能的線程池 //緩存:百度瀏覽過的信息再次訪問 public static?ExecutorService newCachedThreadPool() //創(chuàng)建一個可重用的,具有固定線程數的線程池 public static?ExecutorService newFixedThreadPool(intnThreads) ?? //創(chuàng)建一個只有單線程的線程池,相當于上個方法的參數是1? public static?ExecutorService newSingleThreadExecutor() ?? 這些方法的返回值是ExecutorService對象,該對象表示一個線程池,可以執(zhí)行Runnable對象或者Callable對象代表的線程。它提供了如下方法 Future> submit(Runnable task)Future submit(Callable task)
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ExecutorDemo { public static void main(String[] args) { //創(chuàng)建一個線程池對象,控制要創(chuàng)建幾個線程對象 ExecutorService pool = Executors.newFixedThreadPool(2); //可以執(zhí)行Runnalble對象或者Callable對象代表的線程 pool.submit(new MyRunnable()); pool.submit(new MyRunnable()); //結束線程池 pool.shutdown(); } }(十二) 匿名內部類的方式實現(xiàn)多線程程序
匿名內部類的格式:
new 類名或者接口名( ) { 重寫方法; };
本質:是該類或者接口的子類對象
public class ThreadDemo { public static void main(String[] args) { new Thread() { @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName() + i); } } }.start(); } }
public class RunnableDemo { public static void main(String[] args) { new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName() + i); } } }).start(); } }(十三) 定時器
定時器是一個應用十分廣泛的線程工具,可用于調度多個定時任務以后臺線程的方式執(zhí)行。在Java中,可以通過Timer和TimerTask類來實現(xiàn)定義調度的功能
Timer
·public Timer() public void schedule(TimerTask task, long delay) public void schedule(TimerTask task,long delay,long period)
TimerTask
abstract void run() public boolean cancel()
開發(fā)中
Quartz是一個完全由java編寫的開源調度框架
結尾:如果內容中有什么不足,或者錯誤的地方,歡迎大家給我留言提出意見, 蟹蟹大家 !^_^
如果能幫到你的話,那就來關注我吧?。ㄏ盗形恼戮鶗诠娞柕谝粫r間更新)
在這里的我們素不相識,卻都在為了自己的夢而努力 ?一個堅持推送原創(chuàng)Java技術的公眾號:理想二旬不止
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://m.hztianpu.com/yun/75448.html
摘要:線程可以被稱為輕量級進程。一個守護線程是在后臺執(zhí)行并且不會阻止終止的線程。其他的線程狀態(tài)還有,和。上下文切換是多任務操作系統(tǒng)和多線程環(huán)境的基本特征。在的線程中并沒有可供任何對象使用的鎖和同步器。 原文:Java Multi-Threading and Concurrency Interview Questions with Answers 翻譯:并發(fā)編程網 - 鄭旭東 校對:方騰飛 多...
摘要:多線程和并發(fā)問題是技術面試中面試官比較喜歡問的問題之一。線程可以被稱為輕量級進程。一個守護線程是在后臺執(zhí)行并且不會阻止終止的線程。其他的線程狀態(tài)還有,和。上下文切換是多任務操作系統(tǒng)和多線程環(huán)境的基本特征。 多線程和并發(fā)問題是 Java 技術面試中面試官比較喜歡問的問題之一。在這里,從面試的角度列出了大部分重要的問題,但是你仍然應該牢固的掌握Java多線程基礎知識來對應日后碰到的問題。(...
摘要:但是單核我們還是要應用多線程,就是為了防止阻塞。多線程可以防止這個問題,多條線程同時運行,哪怕一條線程的代碼執(zhí)行讀取數據阻塞,也不會影響其它任務的執(zhí)行。 1、多線程有什么用?一個可能在很多人看來很扯淡的一個問題:我會用多線程就好了,還管它有什么用?在我看來,這個回答更扯淡。所謂知其然知其所以然,會用只是知其然,為什么用才是知其所以然,只有達到知其然知其所以然的程度才可以說是把一個知識點...
摘要:大多數待遇豐厚的開發(fā)職位都要求開發(fā)者精通多線程技術并且有豐富的程序開發(fā)調試優(yōu)化經驗,所以線程相關的問題在面試中經常會被提到。掌握了這些技巧,你就可以輕松應對多線程和并發(fā)面試了。進入等待通行準許時,所提供的對象。 最近看到網上流傳著,各種面試經驗及面試題,往往都是一大堆技術題目貼上去,而沒有答案。 不管你是新程序員還是老手,你一定在面試中遇到過有關線程的問題。Java語言一個重要的特點就...
摘要:超詳細的面試題總結一之基本知識多線程和虛擬機創(chuàng)建線程有幾種不同的方式你喜歡哪一種為什么繼承類實現(xiàn)接口應用程序可以使用框架來創(chuàng)建線程池實現(xiàn)接口。死亡線程方法執(zhí)行結束,或者因異常退出了方法,則該線程結束生命周期。死亡的線程不可再次復生。 超詳細的Java面試題總結(一)之Java基本知識 多線程和Java虛擬機 創(chuàng)建線程有幾種不同的方式?你喜歡哪一種?為什么? 繼承Thread類 實現(xiàn)R...
摘要:下面是線程相關的熱門面試題,你可以用它來好好準備面試。線程安全問題都是由全局變量及靜態(tài)變量引起的。持有自旋鎖的線程在之前應該釋放自旋鎖以便其它線程可以獲得自旋鎖。 最近看到網上流傳著,各種面試經驗及面試題,往往都是一大堆技術題目貼上去,而沒有答案。 不管你是新程序員還是老手,你一定在面試中遇到過有關線程的問題。Java語言一個重要的特點就是內置了對并發(fā)的支持,讓Java大受企業(yè)和程序員...
閱讀 2915·2021-07-30 15:30
閱讀 612·2019-08-30 15:55
閱讀 1678·2019-08-26 17:04
閱讀 692·2019-08-26 11:36
閱讀 2150·2019-08-26 10:58
閱讀 3632·2019-08-23 14:34
閱讀 1618·2019-08-22 18:48
閱讀 2594·2019-08-21 17:51