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

Java?天生就是多線程

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

一、Java 中的線程

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

程序天生就是多線程程序,因為執(zhí)行main() 方法的是一個名稱為main 的線程。

public static void main(String[] args) {

// java 虛擬機線程系統(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());
}
}

上面代碼輸出的結果:

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

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

天生就是多線程的**

1、啟動

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

  • X extends Thread;,然后 X.start
  • X implements Runnable;然后交給 Thread 運行

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

/**
* 擴展自Thread 類
*/
private static class UserThread extends Thread{
@Override
public void run() {
System.out.println("UserThread.run");
}
}
/**
* 擴展自 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對任務(業(yè)務邏輯)的抽象。
  • Thread可以接受任意一個Runnable的實例并執(zhí)行。

2、中止

  • 線程自然終止:要么是run 執(zhí)行完成了,要么是拋出了一個未處理的異常導致線程提前結束。
  • stop:暫停、恢復和停止操作對應在線程ThreadAPI就是suspend()、resume() 和 stop()。但是這些API都是過期的,不再建議使用。不建議使用的主要原因有:以suspend()方法為例,在調(diào)用后,線程不會釋放已占有的資源(比如鎖),而是占有資源進入睡眠狀態(tài),這樣容易引發(fā)死鎖問題。同樣,stop() 方法在終結一個線程時,不會保證線程的資源正常釋放,通常是沒有給予線程完成資源釋放的機會,因此會到導致程序可能工作在不確定的狀態(tài)下。整因為suspend()、resume() 和 stop()方法帶來的副作用,這些方法才會被標注為不建議使用的過期方法中。
  • 中斷:安全的中止則是其它線程通過調(diào)用線程A的interrupt()方法對其進行中止操作,中斷代表著其它線程對A線程打了個招呼,“A, 你要中斷了”,不代表線程A 會立即停止自己的工作,同樣A線程可以不理會這種請求。因為Java 中的線程是協(xié)作式的,不是搶占式。線程通過檢查自身的中斷標志位是否被置為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()){
// 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();
}
// 中斷線程, 其實設置線程的標識位
endTread.interrupt();
}

運行上面的代碼:

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

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

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

先看一下這個方法的源碼:

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

我們來看一下運行效果:

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

3、阻塞

如果一個線程處于阻塞狀態(tài)(如線程調(diào)用了 thread.sleep、thread.join、 thread.wait 等),則線程在檢查中斷標識時,如果發(fā)現(xiàn)中斷標識位true,則會在這些阻塞方法調(diào)用處拋出InterruptedException 異常,并且在拋出異常后會立即將線程的中斷標識位清除,即重新設置為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();
}
// 中斷線程, 其實設置線程的標識位
endTread.interrupt();
}

上面代碼運行結果:

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

代碼運行結果:

4、深入理解run 和 start

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

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

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

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

}

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

5、join 方法

join() 方法是把指定的線程加入到當前線程,可以將兩個交替執(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("學生開始排隊打飯。。。。。");
try {
if (thread != null) thread.join();
// 休眠2 秒
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("學生打飯完成");
}
}
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()+"我打飯完成");
}

代碼運行結果如下:

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

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

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

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

7、守護線程

Daemon(守護)線程是一種支持型線程,因為它主要被用作程序中后臺調(diào) 度以及支持性工作。這意味著,當一個 Java 虛擬機中不存在非 Daemon 線程的 時候,Java 虛擬機將會退出??梢酝ㄟ^調(diào)用??Thread.setDaemon(true)??將線程設置 為Daemon線程。我們一般用不上,比如垃圾回收線程就是Daemon線程。

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

8、synchronized 內(nèi)置鎖

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

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

下面我們看一段代碼,在main 方法中啟動兩個線程,每個線程的count 值都是10000,兩個線程的和應該就是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();
// 啟動兩個線程
Count count1 = new Count(onlyMain);
Count count2 = new Count(onlyMain);
count1.start();
count2.start();
Thread.sleep(50);
System.out.println(onlyMain.count);
}
}

代碼的運行結果是:

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

這是因為,兩個線程同時對count 成員變量進行訪問,才導致輸出結果的錯誤。怎么解決呢?使用synchronized 內(nèi)置鎖。

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

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

這樣我們就能保證每次運行的正確結果了:

9、對象鎖和類鎖

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

但是有一點必須要注意的是,其實類鎖只是一個概念上的東西,并不是真實存在的,類鎖其實鎖的是每個類的對應的class 對象。類鎖和對象鎖之間也是互不干擾的。

二、總結

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

相關文章

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

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

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

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

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

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

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

    Java中復雜的Synchronized關鍵字使用方法詳解

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

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

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

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

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

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

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

    Java生產(chǎn)者消費者模式實例分析

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

    使用opencsv文件讀寫CSV文件

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

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

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

最新評論