欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java?天生就是多線程

 更新時(shí)間:2022年07月01日 15:01:41   作者:半身風(fēng)雪  
這篇文章主要介紹了Java天生就是多線程,程序天生就是多線程程序,因?yàn)閳?zhí)行main()方法的是一個(gè)名稱為main的線程,更多相關(guān)內(nèi)容需要的小伙伴可以參考一下

一、Java 中的線程

一個(gè)Java 程序從main() 方法開始執(zhí)行,然后按照既定的代碼邏輯執(zhí)行,看似沒有其他線程參與,但實(shí)際上Java

程序天生就是多線程程序,因?yàn)閳?zhí)行main() 方法的是一個(gè)名稱為main 的線程。

public static void main(String[] args) {

// java 虛擬機(jī)線程系統(tǒng)的管理接口
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
// 不需要獲取同步的monitor 和synchronizer 信息,僅僅獲取線程和線程堆棧信息
ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false, false);
// 遍歷線程,僅打印線程ID 和線程名稱信息
for (ThreadInfo threadInfo : threadInfos) {
System.out.println("線程ID" + threadInfo.getThreadId() + "線程名" + threadInfo.getThreadName());
}
}

上面代碼輸出的結(jié)果:

  • $\textcolor{red}{Monitor Ctrl-Break}$ 監(jiān)控 Ctrl-Break 中斷信號(hào)的
  • $\textcolor{red}{Signal Dispatcher}$ 分發(fā)處理發(fā)送給 JVM 信號(hào)的線程
  • $\textcolor{red}{ Finalizer }$ 調(diào)用對象 finalize 方法的線程
  • $\textcolor{red}{Reference Handler}$ 清除 Reference 的線程
  • $\textcolor{red}{ main }$ main 線程,用戶程序入口

從上面的例子中,我們能發(fā)現(xiàn),在Java中短短的幾行代碼,就給我們啟動(dòng)了5個(gè)線程,當(dāng)然,不同的版本,啟動(dòng)的線程數(shù)量也不一樣,由此我們可以得出:**Java

天生就是多線程的**

1、啟動(dòng)

線程的啟動(dòng)方式有兩種(源碼中的注釋是這么寫的)參見代碼:cn.enjoyedu.ch1.base.NewThread:

  • X extends Thread;,然后 X.start
  • X implements Runnable;然后交給 Thread 運(yùn)行

示例代碼:(派生自Thread 類,來實(shí)現(xiàn)我們的兩種線程啟動(dòng)方式)

/**
* 擴(kuò)展自Thread 類
*/
private static class UserThread extends Thread{
@Override
public void run() {
System.out.println("UserThread.run");
}
}
/**
* 擴(kuò)展自 Runnable 類
*/
private static class UserRunnable implements Runnable {

@Override
public void run() {
System.out.println("UserRunnable.run");
}
}
public static void main(String[] args) {
UserThread userThread = new UserThread();
userThread.start();
UserRunnable userRunnable = new UserRunnable();
new Thread(userRunnable).start();
}

Thread 和 Runnable 的區(qū)別:

  • Thread 是Java 里對線程的唯一抽象。
  • Runnable是Java對任務(wù)(業(yè)務(wù)邏輯)的抽象。
  • Thread可以接受任意一個(gè)Runnable的實(shí)例并執(zhí)行。

2、中止

  • 線程自然終止:要么是run 執(zhí)行完成了,要么是拋出了一個(gè)未處理的異常導(dǎo)致線程提前結(jié)束。
  • stop:暫停、恢復(fù)和停止操作對應(yīng)在線程ThreadAPI就是suspend()、resume() 和 stop()。但是這些API都是過期的,不再建議使用。不建議使用的主要原因有:以suspend()方法為例,在調(diào)用后,線程不會(huì)釋放已占有的資源(比如鎖),而是占有資源進(jìn)入睡眠狀態(tài),這樣容易引發(fā)死鎖問題。同樣,stop() 方法在終結(jié)一個(gè)線程時(shí),不會(huì)保證線程的資源正常釋放,通常是沒有給予線程完成資源釋放的機(jī)會(huì),因此會(huì)到導(dǎo)致程序可能工作在不確定的狀態(tài)下。整因?yàn)?code>suspend()、resume() 和 stop()方法帶來的副作用,這些方法才會(huì)被標(biāo)注為不建議使用的過期方法中。
  • 中斷:安全的中止則是其它線程通過調(diào)用線程A的interrupt()方法對其進(jìn)行中止操作,中斷代表著其它線程對A線程打了個(gè)招呼,“A, 你要中斷了”,不代表線程A 會(huì)立即停止自己的工作,同樣A線程可以不理會(huì)這種請求。因?yàn)镴ava 中的線程是協(xié)作式的,不是搶占式。線程通過檢查自身的中斷標(biāo)志位是否被置為true來進(jìn)行響應(yīng)。
private static class UserThread extends Thread{
public UserThread(String name){
super(name);
}
@Override
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + "interrupt flag = " + isInterrupted());
while (!isInterrupted()){
// while (!Thread.interrupted()){
// while (true){
System.out.println(threadName+ "is running");
System.out.println(threadName+ "inner interrupt flag = "+ isInterrupted());
}
System.out.println(threadName+ "interrupt flag = " + isInterrupted());
}
}
public static void main(String[] args) {
Thread endTread = new UserThread("endTread");
endTread.start();
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 中斷線程, 其實(shí)設(shè)置線程的標(biāo)識(shí)位
endTread.interrupt();
}

運(yùn)行上面的代碼:

我們發(fā)現(xiàn),在使用isInterrupted()進(jìn)行線程中斷的之后,isInterrupted()會(huì)返回一個(gè)true。

我們一起來看一下isInterrupted() 方法的源碼:

我們再使用一下靜態(tài)的 interrupted()方法,他返回的也是一個(gè)bool 值,

先看一下這個(gè)方法的源碼:

從源碼中我們發(fā)現(xiàn),它返回也是中斷標(biāo)識(shí)符,但是,它把中斷標(biāo)識(shí)符給重新賦值成了true。

我們來看一下運(yùn)行效果:

由此我們可以總結(jié)出:**線程通過方法 isInterrupted()來進(jìn)行判斷是否被中斷,也可以調(diào)用靜態(tài)方法 Thread.interrupted()來進(jìn)行判斷當(dāng)前線程是否被中斷,不過 Thread.interrupted()會(huì)同時(shí)將中斷標(biāo)識(shí)位改寫為 false。**

3、阻塞

如果一個(gè)線程處于阻塞狀態(tài)(如線程調(diào)用了 thread.sleep、thread.join、 thread.wait 等),則線程在檢查中斷標(biāo)識(shí)時(shí),如果發(fā)現(xiàn)中斷標(biāo)識(shí)位true,則會(huì)在這些阻塞方法調(diào)用處拋出InterruptedException 異常,并且在拋出異常后會(huì)立即將線程的中斷標(biāo)識(shí)位清除,即重新設(shè)置為true。

private static class UserThread extends Thread{
public UserThread(String name){
super(name);
}
@Override
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + "interrupt flag = " + isInterrupted());
while (!isInterrupted()){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
System.out.println(threadName+ "inner interrupt flag = "+ isInterrupted());
e.printStackTrace();
}
System.out.println(threadName+ "is running");
}
System.out.println(threadName+ "interrupt flag = " + isInterrupted());
}
}
public static void main(String[] args) {
Thread endTread = new UserThread("endTread");
endTread.start();
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 中斷線程, 其實(shí)設(shè)置線程的標(biāo)識(shí)位
endTread.interrupt();
}

上面代碼運(yùn)行結(jié)果:

那么像這種,我們該怎么去中中斷操作呢?只需要在??catch?? 中調(diào)用??interrupt()?? 方法就可以了

代碼運(yùn)行結(jié)果:

4、深入理解run 和 start

  • Thread類是Java里對線程概念的抽象,可以這樣理解:我們通過??new Thread()?? 其實(shí)只是new出一個(gè)thread的實(shí)例,還沒有和操作系統(tǒng)中真正的線程掛起勾來。只有執(zhí)行了??start()?? 方法后,才實(shí)現(xiàn)了真正意義上的啟動(dòng)線程。
  • ??start()?? 方法讓一個(gè)線程進(jìn)入就緒隊(duì)列等待分配CPU,分到CPU后才調(diào)用??run()??方法,??start()?? 方法不能重復(fù)調(diào)用,如果重復(fù)調(diào)用,就會(huì)拋出異常。
  • run() 方法是業(yè)務(wù)邏輯實(shí)現(xiàn)的地方,本質(zhì)上和任意一個(gè)類的任意一個(gè)成員方法并沒有任何區(qū)別,可以重復(fù)執(zhí)行,也可以單獨(dú)調(diào)用。

那么start() 和 run() 有什么區(qū)別呢?請看代碼:

private static class UserThread extends Thread{
@Override
public void run() {
int i = 90;
while (i > 0){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("I am "+Thread.currentThread().getName()+"and now the i="+ i--);
}
}
}
public static void main(String[] args) {
Thread endTread = new UserThread();
endTread.setName("threadRun");
endTread.start();
}

代碼運(yùn)行結(jié)果:(觀察運(yùn)行結(jié)果,我們可以得出,調(diào)用start() 方法的時(shí)候,執(zhí)行start() 方法的是子線程)

我們修改一下代碼,調(diào)用??run()?? 方法

public static void main(String[] args) {
Thread endTread = new UserThread();
endTread.setName("threadRun");
endTread.run();

}

查看運(yùn)行結(jié)果:(觀察運(yùn)行結(jié)果,我們可以得出,調(diào)用run() 方法的時(shí)候,執(zhí)行run() 方法的是主線程)

5、join 方法

join() 方法是把指定的線程加入到當(dāng)前線程,可以將兩個(gè)交替執(zhí)行的線程合并為順序執(zhí)行。

static class Students implements Runnable {
private Thread thread;
public Students(Thread thread) {
this.thread = thread;
}
public Students() {
}
@Override
public void run() {
System.out.println("學(xué)生開始排隊(duì)打飯。。。。。");
try {
if (thread != null) thread.join();
// 休眠2 秒
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("學(xué)生打飯完成");
}
}
static class Teacher implements Runnable {
@Override
public void run() {
try {
// 休眠2 秒
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("老師開始打飯、、、、、");
System.out.println(Thread.currentThread().getName() + "老師打飯完成。");
}
}
public static void main(String[] args) throws InterruptedException {
Teacher teacher = new Teacher();
Thread teaThread = new Thread(teacher);
Students students = new Students(teaThread);
Thread stuThread = new Thread(students);
stuThread.start();
teaThread.start();
System.out.println("我開始打飯、、、、、");
stuThread.join();
// 讓主線程休眠2 秒
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName()+"我打飯完成");
}

代碼運(yùn)行結(jié)果如下:

由上代碼運(yùn)行結(jié)果,我們可以得出:**在線程B中調(diào)用了線程A的??join()?? 方法,只到線程A 執(zhí)行完畢后,才會(huì)繼續(xù)執(zhí)行線程B的。**

6、線程優(yōu)先級

在 Java 線程中,通過一個(gè)整型成員變量 priority 來控制優(yōu)先級,優(yōu)先級的范 圍從 1~10,在線程構(gòu)建的時(shí)候可以通過??setPriority(int)??方法來修改優(yōu)先級,默認(rèn) 優(yōu)先級是 5,優(yōu)先級高的線程分配時(shí)間片的數(shù)量要多于優(yōu)先級低的線程。

設(shè)置線程優(yōu)先級時(shí),針對頻繁阻塞(休眠或者I/O操作)的線程需要設(shè)置較 高優(yōu)先級,而偏重計(jì)算(需要較多CPU時(shí)間或者偏運(yùn)算)的線程則設(shè)置較低的 優(yōu)先級,確保處理器不會(huì)被獨(dú)占。在不同的 JVM 以及操作系統(tǒng)上,線程規(guī)劃會(huì) 存在差異,有些操作系統(tǒng)甚至?xí)雎詫€程優(yōu)先級的設(shè)定。

7、守護(hù)線程

Daemon(守護(hù))線程是一種支持型線程,因?yàn)樗饕挥米鞒绦蛑泻笈_(tái)調(diào) 度以及支持性工作。這意味著,當(dāng)一個(gè) Java 虛擬機(jī)中不存在非 Daemon 線程的 時(shí)候,Java 虛擬機(jī)將會(huì)退出??梢酝ㄟ^調(diào)用??Thread.setDaemon(true)??將線程設(shè)置 為Daemon線程。我們一般用不上,比如垃圾回收線程就是Daemon線程。

Daemon線程被用作完成支持性工作,但是在 Java 虛擬機(jī)退出時(shí)Daemon線 程中的??finally?? 塊并不一定會(huì)執(zhí)行。在構(gòu)建Daemon線程時(shí),不能依靠??finally?? 塊中 的內(nèi)容來確保執(zhí)行關(guān)閉或清理資源的邏輯。

8、synchronized 內(nèi)置鎖

線程開始運(yùn)行,擁有自己的棧空間,就如同一個(gè)腳本一樣,按照既定的代碼 一步一步地執(zhí)行,直到終止。但是,每個(gè)運(yùn)行中的線程,如果僅僅是孤立地運(yùn)行, 那么沒有一點(diǎn)兒價(jià)值,或者說價(jià)值很少,如果多個(gè)線程能夠相互配合完成工作, 包括數(shù)據(jù)之間的共享,協(xié)同處理事情。這將會(huì)帶來巨大的價(jià)值。

Java支持多個(gè)線程同時(shí)訪問一個(gè)對象或者對象的成員變量,關(guān)鍵字synchronized可以修飾方法或者以同步塊的形式來進(jìn)行使用,它主要確保多個(gè)線 程在同一個(gè)時(shí)刻,只能有一個(gè)線程處于方法或者同步塊中,它保證了線程對變量 訪問的可見性和排他性,又稱為內(nèi)置鎖機(jī)制。

下面我們看一段代碼,在main 方法中啟動(dòng)兩個(gè)線程,每個(gè)線程的count 值都是10000,兩個(gè)線程的和應(yīng)該就是20000。

public class OnlyMain {
private long count = 0;
private Object object = new Object();
public long getCount() {
return count;
}
public void incCount() {
count++;
}
// 線程
private static class Count extends Thread {
private OnlyMain onlyMain;

public Count(OnlyMain onlyMain) {
this.onlyMain = onlyMain;
}
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
// count = count++ = 10000
onlyMain.incCount();
}
}
}
public static void main(String[] args) throws InterruptedException {
OnlyMain onlyMain = new OnlyMain();
// 啟動(dòng)兩個(gè)線程
Count count1 = new Count(onlyMain);
Count count2 = new Count(onlyMain);
count1.start();
count2.start();
Thread.sleep(50);
System.out.println(onlyMain.count);
}
}

代碼的運(yùn)行結(jié)果是:

經(jīng)過多次運(yùn)行,每次運(yùn)行的結(jié)果都不一樣,只有在很少很少的幾率的情況下,才會(huì)出現(xiàn)正確的20000結(jié)果值,這是為什么呢?

這是因?yàn)?,兩個(gè)線程同時(shí)對count 成員變量進(jìn)行訪問,才導(dǎo)致輸出結(jié)果的錯(cuò)誤。怎么解決呢?使用synchronized 內(nèi)置鎖。

修改上面代碼中的incCount() 方法,添加一個(gè)內(nèi)鎖:

public synchronized void incCount() {
count++;
}

這樣我們就能保證每次運(yùn)行的正確結(jié)果了:

9、對象鎖和類鎖

對象鎖是用于對象實(shí)例方法的鎖,或者一個(gè)對象實(shí)例上,類鎖 是用于類的靜態(tài)方法或一個(gè)類的class 上的,我們知道,類的對象實(shí)例可以有很多個(gè),但是每個(gè)類只有一個(gè)class對象,所有不同對象實(shí)例的對象鎖是互不干擾的,但是每個(gè)類只有一個(gè)類鎖。

但是有一點(diǎn)必須要注意的是,其實(shí)類鎖只是一個(gè)概念上的東西,并不是真實(shí)存在的,類鎖其實(shí)鎖的是每個(gè)類的對應(yīng)的class 對象。類鎖和對象鎖之間也是互不干擾的。

二、總結(jié)

到此這篇關(guān)于Java 天生就是多線程的文章就介紹到這了,更多相關(guān)Java 多線程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Hadoop使用hdfs指令查看hdfs目錄的根目錄顯示被拒的原因及解決方案

    Hadoop使用hdfs指令查看hdfs目錄的根目錄顯示被拒的原因及解決方案

    這篇文章主要介紹了Hadoop使用hdfs指令查看hdfs目錄的根目錄顯示被拒的原因及解決方案,分布式部署hadoop,服務(wù)機(jī)只有namenode節(jié)點(diǎn),主機(jī)包含其他所有節(jié)點(diǎn),本文給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2023-10-10
  • SpringBoot+隨機(jī)鹽值+雙重MD5實(shí)現(xiàn)加密登錄

    SpringBoot+隨機(jī)鹽值+雙重MD5實(shí)現(xiàn)加密登錄

    數(shù)據(jù)加密在很多項(xiàng)目上都可以用到,大部分都會(huì)采用MD5進(jìn)行加密,本文主要介紹了SpringBoot+隨機(jī)鹽值+雙重MD5實(shí)現(xiàn)加密登錄,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-02-02
  • Java Swing JTextArea文本區(qū)域的實(shí)現(xiàn)示例

    Java Swing JTextArea文本區(qū)域的實(shí)現(xiàn)示例

    這篇文章主要介紹了Java Swing JTextArea文本區(qū)域的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • Java中復(fù)雜的Synchronized關(guān)鍵字使用方法詳解

    Java中復(fù)雜的Synchronized關(guān)鍵字使用方法詳解

    Synchronized關(guān)鍵字是一個(gè)種鎖,其有很多名字,例如重量級鎖、悲觀鎖、可重入鎖、、非公平、對象鎖等等,這篇文章主要給大家介紹了關(guān)于Java中復(fù)雜的Synchronized關(guān)鍵字使用方法的相關(guān)資料,需要的朋友可以參考下
    2024-01-01
  • java selenium 常見web UI 元素操作及API使用

    java selenium 常見web UI 元素操作及API使用

    本文主要介紹java selenium 常見web UI 元素操作,這里幫大家整理了相關(guān)資料并附示例代碼,有需要的小伙伴可以參考下
    2016-08-08
  • 深入淺析Spring-boot-starter常用依賴模塊

    深入淺析Spring-boot-starter常用依賴模塊

    這篇文章主要介紹了Spring-boot-starter常用依賴模塊及spring boot的兩大優(yōu)點(diǎn),需要的朋友可以參考下
    2018-01-01
  • java Long==Long有趣的現(xiàn)象詳解

    java Long==Long有趣的現(xiàn)象詳解

    這篇文章主要給大家介紹了關(guān)于java Long==Long有趣的現(xiàn)象的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-09-09
  • Java生產(chǎn)者消費(fèi)者模式實(shí)例分析

    Java生產(chǎn)者消費(fèi)者模式實(shí)例分析

    這篇文章主要介紹了Java生產(chǎn)者消費(fèi)者模式,結(jié)合實(shí)例形式分析了java生產(chǎn)者消費(fèi)者模式的相關(guān)組成、原理及實(shí)現(xiàn)方法,需要的朋友可以參考下
    2019-03-03
  • 使用opencsv文件讀寫CSV文件

    使用opencsv文件讀寫CSV文件

    這篇文章主要為大家詳細(xì)介紹了用opencsv文件讀寫CSV文件,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-05-05
  • Java異常:java.net.UnknownHostException產(chǎn)生的原因和解決方案

    Java異常:java.net.UnknownHostException產(chǎn)生的原因和解決方案

    這篇文章主要給大家介紹了關(guān)于Java異常:java.net.UnknownHostException產(chǎn)生的原因和解決方案,這個(gè)異常是java.net包中的一部分,具體說它是類的一個(gè)實(shí)例,異常通常是由主機(jī)名無法解析為IP地址引起的,文中將解決的辦法介紹的非常詳細(xì),需要的朋友可以參考下
    2024-01-01

最新評論