Java中實作多線程通常有兩種方式(其實從Java5開始有三種了,第三種先不說,ps:
我暫時還沒去研究):
1.繼承Thread類
2.實作Runnable接口
雖說有兩種實作方式,但是很明顯在實際開發中實作Runnable這種方式明顯要比繼承Thread多多了,這是因為Runnable擁有天生的優勢:
1.在多線程通路同一資源的情況下,用Runnable接口建立的線程可以處理同一資源,而用Thread建立的線程則獨自處理,各自擁有自己的資源。
2.避免了Java單繼承帶來的局限性。
第二條優勢實在太明顯了,咱們這裡不談
,咱們舉一個爛大街的例子來說明下第一條優勢。
首先通過繼承Thread實作,上代碼:
public class MyThread extends Thread {
private int mTicket = 5;
@Override
public void run() {
for (int i = 0; i < 10; i++) {
if (mTicket > 0) {
System.out.println(Thread.currentThread().getName() + "----mTicket = " + mTicket--);
}
}
}
}
public class ThreadDemo {
public static void main(String arg0[]) {
ArrayList<Thread> threads = new ArrayList<>();
MyThread myThread1 = new MyThread();
MyThread myThread2 = new MyThread();
MyThread myThread3 = new MyThread();
threads.add(myThread1);
threads.add(myThread2);
threads.add(myThread3);
for (Thread thread : threads) {
thread.start();
}
try {
for (Thread thread : threads) {
thread.join();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("所有線程執行完畢!");
}
}
運作結果:
Thread-0----mTicket = 5
Thread-2----mTicket = 5
Thread-2----mTicket = 4
Thread-2----mTicket = 3
Thread-2----mTicket = 2
Thread-2----mTicket = 1
Thread-1----mTicket = 5
Thread-1----mTicket = 4
Thread-0----mTicket = 4
Thread-0----mTicket = 3
Thread-0----mTicket = 2
Thread-0----mTicket = 1
Thread-1----mTicket = 3
Thread-1----mTicket = 2
Thread-1----mTicket = 1
所有線程執行完畢!
咱們開啟了三個線程,每個線程各自賣了5張票,它們之間互不幹擾很和諧。但是現實生活中其實并不是這樣的,火車站官網售票是需要多個線程共同完成一個任務的,繼承Thread這種方式實作不了,咱們試試實作Runnable接口這種方式,上代碼:
public class MyRunnable implements Runnable {
private int mTicket = 5;
@Override
public void run() {
for (int i = 0; i < 10; i++) {
if (mTicket > 0) {
System.out.println(Thread.currentThread().getName() + "----mTicket = " + mTicket--);
}
}
}
}
public class ThreadDemo {
public static void main(String arg0[]) {
ArrayList<Thread> threads = new ArrayList<>();
MyRunnable runnable = new MyRunnable();
Thread thread1 = new Thread(runnable);
Thread thread2 = new Thread(runnable);
Thread thread3 = new Thread(runnable);
threads.add(thread1);
threads.add(thread2);
threads.add(thread3);
for (Thread thread : threads) {
thread.start();
}
try {
for (Thread thread : threads) {
thread.join();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("所有線程執行完畢!");
}
}
第一次運作結果:
Thread-1----mTicket = 4
Thread-1----mTicket = 3
Thread-1----mTicket = 2
Thread-1----mTicket = 1
Thread-0----mTicket = 5
所有線程執行完畢!
第二次運作結果:
Thread-0----mTicket = 5
Thread-0----mTicket = 3
Thread-0----mTicket = 2
Thread-0----mTicket = 1
Thread-2----mTicket = 4
Thread-1----mTicket = 5
所有線程執行完畢!
為何出現兩種不同的結果呢,因為3個Thread對象共同執行Runnable對象中的代碼,線程執行的時機又是難以預測的,很有可能會造成線程不安全。這時隻要加上同步鎖,確定同一時刻隻有一個線程在執行for循環裡的代碼,就可以保證線程安全了。咱們修改下MyRunnable的代碼,上代碼:
public class MyRunnable implements Runnable {
private int mTicket = 5;
@Override
public void run() {
for (int i = 0; i < 10; i++) {
synchronized (this) {
if (mTicket > 0) {
System.out.println(Thread.currentThread().getName() + "----mTicket = " + mTicket--);
}
}
}
}
}
第一次運作結果:
Thread-0----mTicket = 5
Thread-0----mTicket = 4
Thread-0----mTicket = 3
Thread-0----mTicket = 2
Thread-0----mTicket = 1
所有線程執行完畢!
第二次運作結果:
Thread-0----mTicket = 5
Thread-0----mTicket = 4
Thread-1----mTicket = 3
Thread-1----mTicket = 2
Thread-1----mTicket = 1
所有線程執行完畢!
嘿嘿,不管運作多少次,發現結果都是一樣的。