Java多線程
Java多線程
Java實現多線程有四種方式:
1.繼承Thread類;
2.實現Runable接口;
3.實現Callable接口,通過FutureTask包裝器來創建Thread線程;
4.使用ExecutorService、Callable、Future實現有返回結果的多線程;
其中前兩種線程執行完是沒有返回結果的,后兩種是有返回值的。
先貼出一個多線程售票的簡單示例,根據代碼去理解多線程:
/** * 一個售票類,實現Runnable接口重寫run()方法來實現線程 */ @Data public class SellTicket implements Runnable{ //票總數 private int tickets; SellTicket(int tickets){ this.tickets = tickets; } @Override public void run() { while(true) { //鎖,如果這里不加鎖的話,當多個線程同時進入tickets > 0時,可能會出現最后余票為-1,-2的情況 synchronized (this){ if(tickets > 0) { try { Thread.sleep(100); } catch(Exception e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "賣掉一張票,剩下: " + --tickets +"張"); }else{ break; } } } } }
/** * 測試類 */ public class Test { public static void main(String[] args) { SellTicket p1 = new SellTicket(20); Thread t1 = new Thread(p1,"線程1"); Thread t2 = new Thread(p1,"線程2"); Thread t3 = new Thread(p1,"線程3"); //setPriority(),參數為1-10,參數越大,優先級越高,參數超過10會報錯 //t1.setPriority(1); //t2.setPriority(2); //t3.setPriority(10); t1.start(); t2.start(); t3.start(); } }
運行結果:

在測試類中,如果將注釋的優先級放開,那執行結果都會是線程3在售票,當票數更多時,線程1和線程2也會開始售票。當有優先調度需求時,setPriority()就能派上用場。
總結:
1. 前兩種創建多線程的方式差不多,只是因為Java只支持單繼承但可以實現多個接口,所以繼承Thread類來實現接口會有一定的局限性。
2.Thread類本質上是實現了Runnable接口的一個實例,代表一個線程的實例。啟動線程的唯一方法就是通過Thread類的start()實例方法。start()方法是一個native方法,它將啟動一個新線程,并執行run()方法。這種方式實現多線程很簡單,通過自己的類直接extend Thread,并復寫run()方法,就可以啟動新線程并執行自己定義的run()方法。
修改售票示例,通過實現Callable接口實現多線程,并知道線程2賣了多少張票:
/** * 一個售票類,實現Callable接口重寫call()方法來實現線程 */ @Data public class SellTickets implements Callable<Integer> { //票總數 private int tickets; SellTickets(int tickets){ this.tickets = tickets; } @Override public Integer call() { int thread2 = 0; while(true) { //鎖,如果這里不加鎖的話,當多個線程同時進入tickets > 0時,可能會出現最后余票為-1,-2的情況 synchronized (this){ if(tickets > 0) { try { Thread.sleep(100); } catch(Exception e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "賣掉一張票,剩下: " + --tickets +"張"); if("Thread-1".equals(Thread.currentThread().getName())){ thread2++; } }else{ break; } } } return thread2; } }
/** * 測試類 */ public class Test { public static void main(String[] args) { Callable<Integer> callable = new SellTickets(100); FutureTask<Integer> futureTask = new FutureTask<>(callable); Thread thread = new Thread(futureTask); thread.start(); FutureTask<Integer> futureTask2 = new FutureTask<>(callable); Thread thread2 = new Thread(futureTask2); thread2.start(); //獲取線程2的返回值 Integer sum = 0; try{ sum = futureTask2.get(); }catch (Exception e){ e.printStackTrace(); } System.out.println("線程2售票:"+sum+"張"); } }

具體是創建Callable接口的實現類,并實現call()方法。并使用FutureTask類來包裝Callable實現類的對象,且以此FutureTask對象作為Thread對象的target來創建線程。首先,我們發現,在實現Callable接口中,此時不再是run()方法了,而是call()方法,此call()方法作為線程執行體,同時還具有返回值!
浙公網安備 33010602011771號