多线程 java 实例_Java多线程实例学习
1. Java多線程的就緒、運(yùn)行和死亡狀態(tài)
就緒狀態(tài)轉(zhuǎn)換為運(yùn)行狀態(tài):當(dāng)此線程得到處理器資源;
運(yùn)行狀態(tài)轉(zhuǎn)換為就緒狀態(tài):當(dāng)此線程主動(dòng)調(diào)用yield()方法或在運(yùn)行過程中失去處理器資源。
運(yùn)行狀態(tài)轉(zhuǎn)換為死亡狀態(tài):當(dāng)此線程線程執(zhí)行體執(zhí)行完畢或發(fā)生了異常。
此處需要特別注意的是:當(dāng)調(diào)用線程的yield()方法時(shí),線程從運(yùn)行狀態(tài)轉(zhuǎn)換為就緒狀態(tài),但接下來CPU調(diào)度就緒狀態(tài)中的哪個(gè)線程具有一定的隨機(jī)性,因此,可能會(huì)出現(xiàn)A線程調(diào)用了
yield()方法后,接下來CPU仍然調(diào)度了A線程的情況。
由于實(shí)際的業(yè)務(wù)需要,常常會(huì)遇到需要在特定時(shí)機(jī)終止某一線程的運(yùn)行,使其進(jìn)入到死亡狀態(tài)。目前最通用的做法是設(shè)置一boolean型的變量,當(dāng)條件滿足時(shí),使線程執(zhí)行體快速執(zhí)行完畢。如:
1. 代碼
package test;
public class TestStopThread {
public static void main(String[] args) {
MyThread myThread = new MyThread("MyThread");
Thread thread = new Thread(myThread);
for(int i=0; i<100; i++){
System.out.println(Thread.currentThread().getName() + "-->" + i);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(i == 10){
thread.start();
}
if(i == 30){
myThread.stopThread();
}
}
}
}
class MyThread implements Runnable{
boolean stop = false;
private int i = 50;
private String threadName;
public MyThread(String threadName){
this.threadName = threadName;
}
@Override
public void run() {
while (!stop && i>0){
System.out.println(threadName + "-->" + i--);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void stopThread(){
stop = true;
}
}
2. 運(yùn)行結(jié)果:
main-->0
main-->1
main-->2
main-->3
main-->4
main-->5
main-->6
main-->7
main-->8
main-->9
main-->10
main-->11
MyThread-->50
MyThread-->49
main-->12
MyThread-->48
main-->13
MyThread-->47
main-->14
main-->15
MyThread-->46
main-->16
MyThread-->45
MyThread-->44
main-->17
MyThread-->43
main-->18
MyThread-->42
main-->19
MyThread-->41
main-->20
main-->21
MyThread-->40
main-->22
MyThread-->39
MyThread-->38
main-->23
main-->24
MyThread-->37
MyThread-->36
main-->25
main-->26
MyThread-->35
main-->27
MyThread-->34
main-->28
MyThread-->33
MyThread-->32
main-->29
main-->30
MyThread-->31
MyThread-->30
main-->31
main-->32
main-->33
main-->34
main-->35
...
2. Java多線程的阻塞狀態(tài)與線程控制
1. join()
讓一個(gè)線程等待另一個(gè)線程完成才繼續(xù)執(zhí)行。如A線程線程執(zhí)行體中調(diào)用B線程的join()方法,則A線程被阻塞,知道B線程執(zhí)行完為止,A才能得以繼續(xù)執(zhí)行。
(1)代碼實(shí)例:
package test;
public class TestJoin {
public static void main(String[] args) {
MyJoin myJoin = new MyJoin();
Thread thread = new Thread(myJoin, "MyJoin");
for(int i=0; i<30; i++){
System.out.println(Thread.currentThread().getName() + "-->" + i);
if(i == 10){
thread.start();
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(i == 20){
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
class MyJoin implements Runnable{
@Override
public void run() {
for(int i=0; i<20; i++){
System.out.println(Thread.currentThread().getName() + "-->" + i);
}
}
}
(2)運(yùn)行結(jié)果:
main-->0
main-->1
main-->2
main-->3
main-->4
main-->5
main-->6
main-->7
main-->8
main-->9
main-->10
MyJoin-->0
MyJoin-->1
MyJoin-->2
MyJoin-->3
MyJoin-->4
MyJoin-->5
MyJoin-->6
MyJoin-->7
MyJoin-->8
MyJoin-->9
MyJoin-->10
MyJoin-->11
MyJoin-->12
MyJoin-->13
MyJoin-->14
MyJoin-->15
MyJoin-->16
MyJoin-->17
MyJoin-->18
MyJoin-->19
main-->11
main-->12
main-->13
main-->14
main-->15
main-->16
main-->17
main-->18
main-->19
main-->20
main-->21
main-->22
main-->23
main-->24
main-->25
main-->26
main-->27
main-->28
main-->29
可以看到,當(dāng)main線程中join 了MyJoin線程后,會(huì)暫停main線程,直到MyJoin線程執(zhí)行完畢再執(zhí)行main,這就是join方法,說簡(jiǎn)單點(diǎn),就是A線程中調(diào)用B線程join方法,此時(shí),A線程暫停執(zhí)行(阻塞),而B線程執(zhí)行,直到B線程執(zhí)行完畢后A線程繼續(xù)執(zhí)行
2. sleep()
sleep —— 讓當(dāng)前的正在執(zhí)行的線程暫停指定的時(shí)間,并進(jìn)入阻塞狀態(tài)。在其睡眠的時(shí)間段內(nèi),該線程由于不是處于就緒狀態(tài),因此不會(huì)得到執(zhí)行的機(jī)會(huì)。即使此時(shí)系統(tǒng)中沒有任何其他可執(zhí)行的線程,出于sleep()中的線程也不會(huì)執(zhí)行。因此sleep()方法常用來暫停線程執(zhí)行。
前面有講到,當(dāng)調(diào)用了新建的線程的start()方法后,線程進(jìn)入到就緒狀態(tài),可能會(huì)在接下來的某個(gè)時(shí)間獲取CPU時(shí)間片得以執(zhí)行,如果希望這個(gè)新線程盡快執(zhí)行,直接調(diào)用原來線程的sleep(1)即可。
(1)代碼實(shí)例:
package test;
public class TestSleep {
public static void main(String[] args) {
for(int i=0; i<20; i++){
System.out.println(Thread.currentThread().getName() + "-->" + i);
if(i == 10){
new Thread(new MySleep(), "MySleep").start();
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
class MySleep implements Runnable{
@Override
public void run() {
for(int i=0; i<20; i++){
System.out.println(Thread.currentThread().getName() + "-->" + i);
}
}
}
(2)運(yùn)行結(jié)果:
main-->0
main-->1
main-->2
main-->3
main-->4
main-->5
main-->6
main-->7
main-->8
main-->9
main-->10
MySleep-->0
MySleep-->1
MySleep-->2
MySleep-->3
MySleep-->4
MySleep-->5
MySleep-->6
MySleep-->7
MySleep-->8
MySleep-->9
MySleep-->10
MySleep-->11
MySleep-->12
MySleep-->13
MySleep-->14
MySleep-->15
MySleep-->16
MySleep-->17
MySleep-->18
MySleep-->19
main-->11
main-->12
main-->13
main-->14
main-->15
main-->16
main-->17
main-->18
main-->19
3. 后臺(tái)線程(Daemon Thread)
后臺(tái)線程主要是為其他線程(相對(duì)可以稱之為前臺(tái)線程)提供服務(wù),或“守護(hù)線程”。如JVM中的垃圾回收線程。
生命周期:后臺(tái)線程的生命周期與前臺(tái)線程生命周期有一定關(guān)聯(lián)。主要體現(xiàn)在:當(dāng)所有的前臺(tái)線程都進(jìn)入死亡狀態(tài)時(shí),后臺(tái)線程會(huì)自動(dòng)死亡(其實(shí)這個(gè)也很好理解,因?yàn)楹笈_(tái)線程存在的目的在于為前臺(tái)線程服務(wù)的,既然所有的前臺(tái)線程都死亡了,那它自己還留著有什么用)。
設(shè)置后臺(tái)線程:調(diào)用Thread對(duì)象的setDaemon(true)方法可以將指定的線程設(shè)置為后臺(tái)線程。
(1)代碼實(shí)例:
package test;
public class TestDeamon {
public static void main(String[] args) {
MyDeamon myDeamon = new MyDeamon();
Thread thread = new Thread(myDeamon, "MyDeamon");
for(int i=0; i<20; i++){
System.out.println(Thread.currentThread().getName() + "-->" + i);
if(i == 5){
thread.setDaemon(true);
thread.start();
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(i >= 19){
System.out.println("main線程執(zhí)行完畢");
}
}
}
}
class MyDeamon implements Runnable{
@Override
public void run() {
System.out.println("MyDeamon線程開始執(zhí)行");
for(int i=0; i<100; i++){
System.out.println(Thread.currentThread().getName() + "-->" + i);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("MyDeamon線程執(zhí)行完畢");
}
}
(2)運(yùn)行結(jié)果:
main-->0
main-->1
main-->2
main-->3
main-->4
main-->5
main-->6
MyDeamon線程開始執(zhí)行
main-->7
main-->8
main-->9
main-->10
main-->11
main-->12
main-->13
main-->14
main-->15
main-->16
main-->17
main-->18
main-->19
main線程執(zhí)行完畢
MyDeamon-->0
判斷線程是否是后臺(tái)線程:調(diào)用thread對(duì)象的isDeamon()方法。
注:main線程默認(rèn)是前臺(tái)線程,前臺(tái)線程創(chuàng)建中創(chuàng)建的子線程默認(rèn)是前臺(tái)線程,后臺(tái)線程中創(chuàng)建的線程默認(rèn)是后臺(tái)線程。調(diào)用setDeamon(true)方法將前臺(tái)線程設(shè)置為后臺(tái)線程時(shí),需要在start()方法調(diào)用之前。前天線程都死亡后,JVM通知后臺(tái)線程死亡,但從接收指令到作出響應(yīng),需要一定的時(shí)間,前臺(tái)線程main執(zhí)行完畢后,后臺(tái)線程收到指令結(jié)束線程,由于有一定的響應(yīng)時(shí)間,所以執(zhí)行了一段代碼MyDeamon-->0
4. 改變線程的優(yōu)先級(jí)/setPriority()
每個(gè)線程在執(zhí)行時(shí)都具有一定的優(yōu)先級(jí),優(yōu)先級(jí)高的線程具有較多的執(zhí)行機(jī)會(huì)。每個(gè)線程默認(rèn)的優(yōu)先級(jí)都與創(chuàng)建它的線程的優(yōu)先級(jí)相同。main線程默認(rèn)具有普通優(yōu)先級(jí)。
設(shè)置線程優(yōu)先級(jí):setPriority(int priorityLevel)。參數(shù)priorityLevel范圍在1-10之間,常用的有如下三個(gè)靜態(tài)常量值:
MAX_PRIORITY:10
MIN_PRIORITY:1
NORM_PRIORITY:5
注:具有較高線程優(yōu)先級(jí)的線程對(duì)象僅表示此線程具有較多的執(zhí)行機(jī)會(huì),而非優(yōu)先執(zhí)行。
(1)代碼實(shí)例:
package test;
public class TestPriority {
public static void main(String[] args) {
MyPriority myPriority = new MyPriority();
Thread thread = new Thread(myPriority, "MyPriority");
thread.setPriority(Thread.MAX_PRIORITY);
thread.start();
for(int i=0; i<20; i++){
System.out.println(Thread.currentThread().getName() + "-->" + i);
}
}
}
class MyPriority implements Runnable{
@Override
public void run() {
for(int i=0; i<20; i++){
System.out.println(Thread.currentThread().getName() + "-->" + i);
}
}
}
(2)運(yùn)行結(jié)果1:
MyPriority-->0
MyPriority-->1
MyPriority-->2
MyPriority-->3
MyPriority-->4
MyPriority-->5
MyPriority-->6
MyPriority-->7
MyPriority-->8
MyPriority-->9
MyPriority-->10
MyPriority-->11
MyPriority-->12
MyPriority-->13
MyPriority-->14
MyPriority-->15
MyPriority-->16
MyPriority-->17
MyPriority-->18
MyPriority-->19
main-->0
main-->1
main-->2
main-->3
main-->4
main-->5
main-->6
main-->7
main-->8
main-->9
main-->10
main-->11
main-->12
main-->13
main-->14
main-->15
main-->16
main-->17
main-->18
main-->19
運(yùn)行結(jié)果2:
main-->0
MyPriority-->0
MyPriority-->1
MyPriority-->2
MyPriority-->3
MyPriority-->4
MyPriority-->5
MyPriority-->6
MyPriority-->7
MyPriority-->8
MyPriority-->9
MyPriority-->10
MyPriority-->11
MyPriority-->12
MyPriority-->13
MyPriority-->14
MyPriority-->15
MyPriority-->16
MyPriority-->17
MyPriority-->18
MyPriority-->19
main-->1
main-->2
main-->3
main-->4
main-->5
main-->6
main-->7
main-->8
main-->9
main-->10
main-->11
main-->12
main-->13
main-->14
main-->15
main-->16
main-->17
main-->18
main-->19
可以看到,當(dāng)設(shè)置了線程優(yōu)先級(jí)后,優(yōu)先級(jí)高的具有較多的執(zhí)行機(jī)會(huì),但是并不一定優(yōu)先執(zhí)行,運(yùn)行結(jié)果1和2有些許不同,1中MyPriority線程先執(zhí)行,2中main線程先執(zhí)行了一段時(shí)間,后讓給優(yōu)先級(jí)高的MyPriority線程,可見,證實(shí)了"具有較高線程優(yōu)先級(jí)的線程對(duì)象僅表示此線程具有較多的執(zhí)行機(jī)會(huì),而非優(yōu)先執(zhí)行。"
5. 線程讓步:yield()
使當(dāng)前線程從執(zhí)行狀態(tài)(運(yùn)行狀態(tài))變?yōu)榭蓤?zhí)行態(tài)(就緒狀態(tài))。cpu會(huì)從眾多的可執(zhí)行態(tài)里選擇,也就是說,當(dāng)前也就是剛剛的那個(gè)線程還是有可能會(huì)被再次執(zhí)行到的,并不是說一定會(huì)執(zhí)行其他線程而該線程在下一次中不會(huì)執(zhí)行到了。調(diào)用yield方法后,該線程就會(huì)把CPU時(shí)間讓掉,讓其他或者自己的線程執(zhí)行(也就是誰先搶到誰執(zhí)行)
同時(shí),yield()方法還與線程優(yōu)先級(jí)有關(guān),當(dāng)某個(gè)線程調(diào)用yiled()方法從運(yùn)行狀態(tài)轉(zhuǎn)換到就緒狀態(tài)后,CPU從就緒狀態(tài)線程隊(duì)列中只會(huì)選擇與該線程優(yōu)先級(jí)相同或優(yōu)先級(jí)更高的線程去執(zhí)行。
(1)代碼實(shí)例:
package test;
public class TestYield {
public static void main(String[] args) {
MyYield1 myYield1 = new MyYield1();
MyYield2 myYield2 = new MyYield2();
Thread thread1 = new Thread(myYield1, "MyYield1");
Thread thread2 = new Thread(myYield2, "MyYield2");
thread1.setPriority(Thread.MAX_PRIORITY);
thread2.setPriority(Thread.MIN_PRIORITY);
thread1.start();
thread2.start();
for(int i=0; i<50; i++){
System.out.println(Thread.currentThread().getName() + "-->" + i);
if(i == 10){
Thread.yield();
}
}
}
}
class MyYield1 implements Runnable{
@Override
public void run() {
for(int i=0; i<30; i++){
System.out.println(Thread.currentThread().getName() + "-->" + i);
}
}
}
class MyYield2 implements Runnable{
@Override
public void run() {
for(int i=0; i<30; i++){
System.out.println(Thread.currentThread().getName() + "-->" + i);
}
}
}
(2)運(yùn)行結(jié)果:
main-->0
main-->1
main-->2
MyYield1-->0
MyYield1-->1
MyYield1-->2
MyYield1-->3
MyYield1-->4
MyYield1-->5
MyYield1-->6
MyYield1-->7
MyYield1-->8
MyYield1-->9
MyYield1-->10
MyYield1-->11
MyYield1-->12
MyYield1-->13
MyYield1-->14
MyYield1-->15
MyYield1-->16
MyYield1-->17
MyYield1-->18
MyYield1-->19
MyYield1-->20
MyYield1-->21
MyYield1-->22
MyYield1-->23
MyYield1-->24
MyYield1-->25
MyYield1-->26
MyYield1-->27
MyYield1-->28
MyYield1-->29
main-->3
main-->4
main-->5
main-->6
main-->7
main-->8
main-->9
main-->10
main-->11
main-->12
main-->13
main-->14
main-->15
main-->16
main-->17
main-->18
main-->19
main-->20
main-->21
main-->22
main-->23
main-->24
main-->25
main-->26
main-->27
main-->28
main-->29
main-->30
main-->31
main-->32
main-->33
main-->34
main-->35
main-->36
main-->37
main-->38
main-->39
main-->40
main-->41
main-->42
main-->43
main-->44
main-->45
main-->46
main-->47
main-->48
main-->49
MyYield2-->0
MyYield2-->1
MyYield2-->2
MyYield2-->3
MyYield2-->4
MyYield2-->5
MyYield2-->6
MyYield2-->7
MyYield2-->8
MyYield2-->9
MyYield2-->10
MyYield2-->11
MyYield2-->12
MyYield2-->13
MyYield2-->14
MyYield2-->15
MyYield2-->16
MyYield2-->17
MyYield2-->18
MyYield2-->19
MyYield2-->20
MyYield2-->21
MyYield2-->22
MyYield2-->23
MyYield2-->24
MyYield2-->25
MyYield2-->26
MyYield2-->27
MyYield2-->28
MyYield2-->29
總結(jié)
以上是生活随笔為你收集整理的多线程 java 实例_Java多线程实例学习的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 任正非重申不造车!赛力斯回应:华为合作模
- 下一篇: java的应用程序开发_开发一个Java