java多线程编程--基础篇
一、基本概念
a、操作系統(tǒng)中進程與線程的概念
現(xiàn)在的操作系統(tǒng)是多任務操作系統(tǒng)。多線程是實現(xiàn)多任務的一種方式。 進程是指一個內存中運行的應用程序,每個進程都有自己獨立的一塊內存空間,
一個進程中可以啟動多個線程。比如在Windows系統(tǒng)中,一個運行的exe就是一個進程。
線程是指進程中的一個執(zhí)行流程,一個進程中可以運行多個線程。比如java.exe進程中可以運行很多線程。線程總是屬于某個進程,進程中的多個線程共享進程的內存空間。
“同時”執(zhí)行是人的感覺,在線程之間實際上輪換執(zhí)行。
b、Java中的線程 在Java中,“線程”指兩件不同的事情: ??????
?????????? a、java.lang.Thread類的一個實例。 ??????
???????????b、線程的執(zhí)行。
使用java.lang.Thread類或者java.lang.Runnable接口編寫代碼來定義、實例化和啟動新線程。
一個Thread類實例只是一個對象,像Java中的任何其他對象一樣,具有變量和方法,在堆上完成對象的創(chuàng)建和銷毀。
Java中,每個線程都有一個調用棧,即使不在程序中創(chuàng)建任何新的線程,線程也在后臺運行著。
一個Java應用總是從main()方法開始運行,mian()方法運行在一個線程內,它被稱為主線程。
一旦創(chuàng)建一個新的線程,就產(chǎn)生一個新的調用棧。線程總體分兩類:用戶線程和守護線程。
當所有用戶線程執(zhí)行完畢的時候,JVM自動關閉。但是守護線程卻獨立于JVM,守護線程一般是由操作系統(tǒng)或者用戶自己創(chuàng)建的。
二、線程的創(chuàng)建與啟動
a、定義線程
1、繼承java.lang.Thread類。
此類中有個run()方法,應該注意其用法: public void run() 如果該線程是使用獨立的 Runnable 運行對象構造的,則調用該 Runnable 對象的 run 方法;否則,該方法不執(zhí)行任何操作并返回。??Thread 的子類應該重寫該方法。
2、實現(xiàn)java.lang.Runnable接口。
void run() 使用實現(xiàn)接口 Runnable 的對象創(chuàng)建一個線程時,啟動該線程將導致在獨立執(zhí)行的線程中調用對象的 run 方法。??
方法 run 的常規(guī)協(xié)定是,它可能執(zhí)行任何所需的操作。
b、實例化線程
1、如果是繼承java.lang.Thread類的線程,則直接new即可。
即使用的時候Thread a=new tThread();2、如果是實現(xiàn)了java.lang.Runnable接口的類,則用Thread的構造方法:
Thread(Runnable target) Thread(Runnable target, String name) Thread(ThreadGroup group, Runnable target) Thread(ThreadGroup group, Runnable target, String name) Thread(ThreadGroup group, Runnable target, String name, long stackSize)?
rThread a=new rThread();//此處可以使用各個構造函數(shù) Thread b=new Thread(a);?
c、啟動線程
??????? 在線程的Thread對象上調用start()方法,而不是run()或者別的方法。 在調用start()方法之前:線程處于新狀態(tài)中,新狀態(tài)指有一個Thread對象,但還沒有一個真正的線程。 在調用start()方法之后,發(fā)生了一系列復雜的事情:啟動新的執(zhí)行線程(具有新的調用棧); 該線程從新狀態(tài)轉移到可運行狀態(tài); 當該線程獲得機會執(zhí)行時,其目標run()方法將運行。
start()方法后,run()方法并沒有執(zhí)行。
注意:對Java來說,run()方法沒有任何特別之處。像main()方法一樣,它只是新線程知道調用的方法名稱(和簽名)。因此,在Runnable上或者Thread上調用run方法是合法的,但并不啟動新的線程,所以通常不使用
d、基本例子
?1、實現(xiàn)Runnable接口的多線程例子
package com.yunhe.thread; /*** 實現(xiàn)Runable接口的類* */ public class DoSomething implements Runnable {private String name;public DoSomething(String name) {this.name = name;}public void run() {for (int i = 0; i < 5; i++) {for (long k = 0; k < 100000000; k++);System.out.println(name + ": " + i);}} }測試類代碼:
package com.yunhe.thread; /*** 實現(xiàn)Runnable的線程的測試類*/public class TestRunnable {public static void main(String[] args) {DoSomething ds1=new DoSomething("tianti");DoSomething ds2=new DoSomething("yunhe");Thread t1=new Thread(ds1);Thread t2=new Thread(ds2);t1.start();t2.start();}}
運行結果:
tianti: 0 yunhe: 0 yunhe: 1 tianti: 1 yunhe: 2 tianti: 2 yunhe: 3 tianti: 3 yunhe: 4 tianti: 42、繼承Thread實現(xiàn)線程的例子
package com.yunhe.thread; /*** 繼承Thread的線程類* */ public class DoOtherthing extends Thread {public DoOtherthing(String name) {super(name);}@Overridepublic void run() {// TODO Auto-generated method stubsuper.run();for (int i = 0; i < 5; i++) {for (long k = 0; k < 1000000000; k++);System.out.println(this.getName() + ": " + i);}}}測試類代碼:
package com.yunhe.thread; /*** 繼承Thread類* */ public class DoOtherthing extends Thread {public DoOtherthing(String name) {super(name);}@Overridepublic void run() {// TODO Auto-generated method stubsuper.run();for (int i = 0; i < 5; i++) {for (long k = 0; k < 1000000000; k++);System.out.println(this.getName() + ": " + i);}}}運行結果:
tianti: 0 yunhe: 0 tianti: 1 yunhe: 1 tianti: 2 yunhe: 2 tianti: 3 yunhe: 3 tianti: 4 yunhe: 4對于上面的多線程程序代碼來說,輸出的結果是不確定的。
其中for (long k = 0; k < 100000000; k++);是模擬非常耗時的操作,k值上限較小的時候輸出是順序的,較大的時候是不穩(wěn)定的交叉輸出。
e、一些常見的問題
1、線程的名字,一個運行中的線程總是有名字的,名字有兩個來源,一個是JVM虛擬機自己給的名字,一個是你自己的定的名字。在沒有指定線程名字的情況下,JVM虛擬機總會為線程指定名字,并且主線程的名字總是main,非主線程的名字不確定。
2、線程都可以設置名字,也可以獲取線程的名字,連主線程也不例外。
3、獲取當前線程的對象的方法是:Thread.currentThread();
4、在上面的代碼中,只能保證:每個線程都將啟動,每個線程都將運行直到完成。一系列線程以某種順序啟動并不意味著將按該順序執(zhí)行。對于任何一組啟動的線程來說,調度程序不能保證其執(zhí)行次序,持續(xù)時間也無法保證。
5、當線程目標run()方法結束時該線程完成。
6、一旦線程啟動,它就永遠不能再重新啟動。只有當線程是新的線程的時候才可以被啟動,并且只能一次。一個可運行的線程(就緒狀態(tài))或死線程可以被重新啟動。
7、線程的調度是JVM的一部分,在一個CPU的機器上上,實際上一次只能運行一個線程。一次只有一個線程棧執(zhí)行。JVM線程調度程序決定實際運行哪個處于可運行狀態(tài)的線程(就緒狀態(tài))。
眾多可運行線程中的某一個會被選中做為當前線程。可運行線程被選擇運行的順序是沒有保障的。
8、盡管通常采用隊列形式,但這是沒有保障的。隊列形式是指當一個線程完成“一輪”時,它移到可運行隊列的尾部等待,直到它最終排隊到該隊列的前端為止,它才能被再次選中。事實上,我們把它稱為可運行池而不是一個可運行隊列,目的是幫助認識線程運行并不都是以某種有保障的順序排列來調度線程。
9、盡管我們不能控制線程調度的順序,但可以通過別的方式來影響線程調度的方式。
?
?
?
轉載于:https://www.cnblogs.com/shudonghe/p/3276387.html
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的java多线程编程--基础篇的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [置顶] ProDinner体验
- 下一篇: 【PAT】1009. Product o