程序和線程的關系
多個線程構成一個程序,線程是程序中的一個元素,例如QQ.exe檢視電腦程序的時候發現隻有一個程序,但是我們可以同時和多個使用者聊天交流,而且可以一邊聊天,刷空間之類。對每一個使用者的聊天就是一個線程,多個使用者的互動構成程序。
示範一個不使用多線程的Demo,也就是單線程
public class SingleDemo{
public static void main(String[] args){
MyThread myThread = new MyThread();
myThread.run();
while(true){
System.out.println("Main方法在運作");
}
}
}
class MyThread{
public void run(){
while (true){
System.out.println("MyThread類的run()方法在運作");
}
}
}
根據demo可以知道mian中的run方法永遠都不可能被執行
一張圖說明何為單線程和多線程!
從圖中很清晰表明我們使用多線程的原因
繼承Thread建立多線程
public class DemoThread{
public static void main(String[] args){
MyThread myThread = new MyThread();
myThread.start(); //通過start()開啟了一個新的線程
while(true){
System.out.println("run()方法在運作");
}
}
}
class MyThread extends Thread {
public void run(){
while(true){
System.out.println("MyThread類的run()方法在運作");
}
}
}
顯示結果
實作Runnable接口建立多線程
public class DemoRunnable{
public static void main(String[] args){
RunnableDemo runnable = new RunnableDemo();
Thread mythread = new Thread(runnable);
mythread.start();
while(true){
System.out.println("main類的run()方法在運作");
}
}
}
class RunnableDemo implements Runnable{
public void run(){
while(true){
System.out.println("RunnableDemo類的run()方法在運作");
}
}
}
顯示結果
目前實作多線程的方式繼承Thread,另一種實作Runnable接口。
上述Demo是利用Thread(Runnable target)這個構造函數實作的,Runnable是一個接口其中隻有一個run()方法,在調用Thread時,看一下Thread的類結構就知道,其實實作的是接口Runnable中的方法。是以兩種多線程實作方式具有多态關系。
Thread VS Runnable
先說一個例子,火車站售票會牽扯到一個資源共享的問題,資源就是車票,每個售票都相當與一個線程,假如有100張票,每張票理論上都隻能買一個人,下面看Thread和Runnable的處理方式
繼承Thread
public class DemoExceple{
public static void main(String[] args){
new TicketWindow().start();
new TicketWindow().start();
new TicketWindow().start();
new TicketWindow().start();
}
}
class TicketWindow extends Thread{
private int tickets = 100;
public void run(){
while(true){
if(tickets>0){
Thread th = Thread.currentThread();
String name = th.getName();
System.out.println(name+"正在發售第"+tickets--+"張票");
}
}
}
}
運作結果
根據這個運作結果,發現每一張票都被重複賣了四次,明顯這種多線程的方式并不太适合資源共享的問題。
實作Runnable接口
public class RunnableDemoTest{
public static void main(String[] args){
TicketWindow tw = new TicketWindow();
new Thread(tw,"視窗1").start();
new Thread(tw,"視窗2").start();
new Thread(tw,"視窗3").start();
new Thread(tw,"視窗4").start();
}
}
class TicketWindow implements Runnable{
private int tickets = 100;
public void run(){
while(true){
if(tickets>0){
Thread th = Thread.currentThread();
String th_name = th.getName();
System.out.println(th_name+"正在發售第"+tickets--+"張票");
}
}
}
}
運作結果
根據運作結果發現使用Runnable接口剛好能解決我們資源共享的問題。
為什麼Thread不行,而Runnable就可以?
Thread方式中建立了4個Thread對象,4個線程分别執行4個對象中的代碼,是以4個線程是獨立的去完成賣票任務
Runnable方式,同樣建立了4個Thread對象,但是隻有一個Runnable對象,4個Thread對象共享Runnable中的代碼,是以,便會出現4個線程同時完成賣票的任務的結果。如果建立4個Runnable對象,分别做為參數傳入4個Thread中,結果會和Thread方式一樣的。
其實實作Runnable接口的線程中如果出現休眠,在資源共享也會出現非線程安全的問題,最根本的解決方式資源共享的問題還是同步鎖(synchronized)的機制。
結論
根據上述兩種情況,其實Runnable和Thread能完成相同的功能,畢竟Thread也是實作Runnable,兩者根本的差別一個是繼承,一個是實作。
1、Runnable相當于一個作業,而Thread才是真正的處理線程。通過new Thread(Runnable target)把作業交給線程去處理,這樣達到松耦合的效果,也是符合面向對象中組合的使用。