前言:
每個正在系統上運行的程序都是一個進程。每個進程包含一到多個線程。
線程是一組指令的集合,或者是程序的特殊段,它可以在程序里獨立執行。也可以把它理解為代碼運行的上下文。所以線程基本上是輕量級的進程,它負責在單個程序里執行多任務。通常由操作系統負責多個線程的調度和執行。
使用線程可以把占據時間長的程序中的任務放到后台去處理,程序的運行速度可能加快,在一些等待的任務實現上如用戶輸入、文件讀寫和網絡收發數據等,線程就比較有用了。在這種情況下可以釋放一些珍貴的資源如內存占用等等。
如果有大量的線程,會影響性能,因為操作系統需要在它們之間切換,更多的線程需要更多的內存空間,線程的中止需要考慮其對程序運行的影響。通常塊模型數據是在多個線程間共享的,需要防止線程死鎖情況的發生。
正文:
兩種實現多線程的方式,繼承Thread類或者實現Runnable接口。
繼承
Thread類 :
package
com.zsz.thread;
public
class
MyThread
extends
Thread {
private
int
index
;
public
MyThread(
int
index){
this
.
index
= index;
}
public
void
run () {
for
(
int
i=0;i<5;i++){
System.
out
.println(
index
+
":"
+i);
}
}
public
static
void
main(String[] args){
MyThread MyThread =
new
MyThread(1);
MyThread MyThread2 =
new
MyThread(2);
MyThread.start();
MyThread2.start();
}
}
可能的運行結果:
1:0
2:0
1:1
2:1
1:2
2:2
1:3
2:3
1:4
2:4
由於執行CPU占用時間被切換,線程狀態的切換,導致執行順序的不同。
實現
Runnable接口:
package
com.zsz.thread;
public
class
MyRunnable
implements
Runnable{
private
int
index
;
public
MyRunnable(
int
index){
this
.
index
= index;
}
@Override
public
void
run() {
for
(
int
i=0;i<5;i++){
System.
out
.println(
index
+
":"
+i);
}
}
public
static
void
main(String[] args){
MyRunnable MyRunnable1 =
new
MyRunnable(1);
Thread Thread1 =
new
Thread(MyRunnable1);
MyRunnable MyRunnable2 =
new
MyRunnable(2);
Thread Thread2 =
new
Thread(MyRunnable2);
Thread1.start();
Thread2.start();
}
}
可能的結果:
1:0
1:1
1:2
2:0
2:1
2:2
2:3
2:4
1:3
1:4
場景應用:
一、車站多個窗口買票,車票總數是一定的,實現Runnable可以共享總票數。
package
com.zsz.thread;
class
SaleTicket
implements
Runnable{
private
int
ret
= 5;
//剩下票數
private
int
num
;
//一次買票張數
public
SaleTicket(
int
num){
this
.
num
= num;
}
@Override
public
void
run() {
synchronized
(
this
){
if
(
num
>
ret
){
System.
out
.println(
"余票不足"
);
return
;
}
ret
=
ret
-
num
;
System.
out
.println(
"出票"
+
num
+
"張成功,剩余票數:"
+
ret
);
//出票成功
}
}
}
public
class
MyRunnable
extends
Thread{
public
static
void
main(String[] args){
SaleTicket saleTicket1 =
new
SaleTicket(1);
new
Thread(saleTicket1).start();
new
Thread(saleTicket1).start();
new
Thread(saleTicket1).start();
new
Thread(saleTicket1).start();
new
Thread(saleTicket1).start();
new
Thread(saleTicket1).start();
new
Thread(saleTicket1).start();
}
}
可能的執行結果:
出票1張成功,剩余票數:4
出票1張成功,剩余票數:3
出票1張成功,剩余票數:2
出票1張成功,剩余票數:1
出票1張成功,剩余票數:0
余票不足
余票不足
注:考慮數據同步和線程安全,synchronized (this)確保同步,確保一個時刻只有一個線程占用
synchronized 程序塊,
否則會出現線程不安全的情況,。
實現Runnable接口相比繼承Thread類:
1):適合多個相同的程序代碼的線程去處理同一個資源
2):可以避免java中的單繼承的限制
3):增加程序的健壯性,代碼可以被多個線程共享,代碼和數據獨立。
1):適合多個相同的程序代碼的線程去處理同一個資源
2):可以避免java中的單繼承的限制
3):增加程序的健壯性,代碼可以被多個線程共享,代碼和數據獨立。
main方法其實也是一個線程。
線程其他情況:
線程休眠:
Thread.sleep(
2000
);
線程中斷:
new
Thread(
new Runnable()
)
.interrupt();
線程優先級:
new
Thread(
new Runnable()
)
.setPriority(8);
線程的狀態及說明:
1、新建狀態(New):新創建了一個線程對象。
2、就緒狀態(Runnable):線程對象創建后,其他線程調用了該對象的start()方法。該狀態的線程位於可運行線程池中,變得可運行,等待獲取CPU的使用權。
3、運行狀態(Running):就緒狀態的線程獲取了CPU,執行程序代碼。
4、阻塞狀態(Blocked):阻塞狀態是線程因為某種原因放棄CPU使用權,暫時停止運行。直到線程進入就緒狀態,才有機會轉到運行狀態。阻塞的情況分三種:
4.1、等待阻塞:運行的線程執行wait()方法,JVM會把該線程放入等待池中。
4.2、同步阻塞:運行的線程在獲取對象的同步鎖時,若該同步鎖被別的線程占用,則JVM會把該線程放入鎖池中。
4.3、其他阻塞:運行的線程執行sleep()或join()方法,或者發出了I/O請求時,JVM會把該線程置為阻塞狀態。當sleep()狀態超時、join()等待線程終止或者超時、或者I/O處理完畢時,線程重新轉入就緒狀態。
5、死亡狀態(Dead):線程執行完了或者因異常退出了run()方法,該線程結束生命周期。
關鍵字
volatile
用volatile修飾的變量,線程在每次使用變量的時候,都會讀取變量修改后的最的值。volatile很容易被誤用,用來進行原子性操作。
volatile不用做原子性操作的原因是:線程在運行時會在線程內存塊中變量副本,之后,主內存中的變量與線程內的變量不聯系,當運行結束時,線程內的變量會將值同步給主內存,因而會有可能出現線程不安全。
有相關問題,可以提出來一起討論。后續將會張貼一些進階的多線程、線程池內容。
博客園原文地址:http://www.cnblogs.com/zhongshengzhen