面試-實現多執行緒的方式

尹吉歡發表於2018-06-29

Java中實現多執行緒的方式有下面三種:

  1. 繼承Thread類,重寫run方法
package fs;

public class ThreadTest {
	public static void main(String[] args) {
		new MyThread().start();
	}
}

class MyThread extends Thread {
	
	@Override
	public void run() {
		System.out.println("我是一個執行緒,我叫:"+Thread.currentThread().getName());
	}
	
}
  1. 實現Runnable介面,重寫run方法
package fs;

public class ThreadTest {
	public static void main(String[] args) {
		new Thread(new MyRunnable()).start();
	}
}

class MyRunnable implements Runnable {
	
	@Override
	public void run() {
		System.out.println("我是一個執行緒,我叫:"+Thread.currentThread().getName());
	}
	
}
  1. 通過Callable和FutureTask建立執行緒(最終還是Thread啟動)
package fs;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class ThreadTest {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		MyCallable call = new MyCallable();
		FutureTask<String> task = new FutureTask<String>(call);
		new Thread(task).start();
		String result = task.get();
		System.out.println(result);
	}
}

class MyCallable implements Callable<String> {
	
	@Override
	public String call() throws Exception {
		return "Hello";
	}
	
}

上面的三種方式的區別在哪呢?

  • 實現方式不同
    第一種是繼承的方式,第二種和第三種都是實現介面的方式

  • 返回值
    第一種和第二種有一個共同的特點就是沒有返回值,而第三種是有返回值的

  • 擴充套件性
    在Java中我們都知道類只能單繼承,如果我們自己建立的執行緒類是通過繼承Thread類的方法來實現的,那麼這個自定義類就不能再去擴充套件其他的類,也就是說不能再去實現更加複雜的功能。
    如果我們用實現Runnable介面的方式來建立執行緒類,這樣就可以避免Java單繼承所帶來的侷限性,通過介面多實現的特性進行擴充套件。

  • 資源共享/不共享
    繼承的方式相當於一個執行緒只能幹一件事情,介面實現可以多個多個執行緒幹同一件事情

下面通過一段簡單的程式碼來進行講解

定義一個售票視窗類

class TicketWindow extends Thread {
    int count = 100;
   
    @Override
    public void run() {
        System.out.println("視窗:"+Thread.currentThread().getName() + ":賣票啦" + count--);
    }
    
}

public class ThreadTest {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		
		for (int i = 0; i < 5; i++) {
			TicketWindow t = new TicketWindow();
			t.start();
		}
	}
}

執行結果如下:

視窗:Thread-1:賣票啦100
視窗:Thread-0:賣票啦100
視窗:Thread-2:賣票啦100
視窗:Thread-3:賣票啦100
視窗:Thread-4:賣票啦100

每個執行緒都有自己的票總量,處理的都是自己的票,就是說每個視窗各自賣各自的票,這就是繼承實現執行緒的特點,一個執行緒處理一件事情

下面來看介面實現方式的程式碼

class TicketWindow2 implements Runnable {
    int count = 100;
   
    @Override
    public void run() {
        System.out.println("視窗2:"+Thread.currentThread().getName() + ":賣票啦" + count--);
    }
    
}

public class ThreadTest {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		TicketWindow2 t2 = new TicketWindow2(); 
		for (int i = 0; i < 5; i++) {
			new Thread(t2).start();
		}
	}
}

執行結果如下:

視窗2:Thread-0:賣票啦100
視窗2:Thread-3:賣票啦97
視窗2:Thread-1:賣票啦99
視窗2:Thread-2:賣票啦98
視窗2:Thread-4:賣票啦96

總共5個視窗也就是5個執行緒,執行的業務邏輯是相同的,相當於賣的是共享的票,我賣完了,你那邊就不能賣了,實際上也是這樣的,我們在12306買票就是這個邏輯,當然這邊沒有考慮到併發下票數超賣的情況。介面實現的方式可以讓多個執行緒做同一件事情。

更多技術分享請關注微信公眾號:猿天地

歡迎加入我的知識星球,一起交流技術,免費學習猿天地的課程(http://cxytiandi.com/course)

PS:目前星球中正在星主的帶領下組隊學習Spring Cloud,等你哦!

微信掃碼加入猿天地知識星球

猿天地

相關文章