Java——多執行緒的簡單實現
中高階架構師的必經之路:
高可用、高併發、高效能網站開發
多執行緒基本概念:
多個程序同時進
執行緒:排程和執行的單位(cpu的排程)
程序:作為資源分配的單位(作業系統的分配)
執行緒是程序的一部分
使用者執行緒和守護執行緒
使用者執行緒:java虛擬機器所有使用者執行緒dead後,程式就會結束
守護執行緒:輔助使用者執行緒進行工作,不適用於I/O輸入輸出以及計算操作,避免程式結束後,任務不能執行完。
守護執行緒使用情景:
1、JVM垃圾回收
2、記憶體管理
3、資料庫連線池監聽狀態等
多執行緒的實現
1、基礎Thread類,實現run方法
例項1:
//多實現少繼承://繼承也許需要繼承多個類而實現不需要考慮這些public class test10 { //建立執行緒:1、繼承Thread+重寫run //2、建立子類物件+start public static void main(String[] args){ } }class MyThread extends Thread{ public void run(){ for(int i = 0;i<20;i++){ System.out.println("聽歌"); } } public static void
執行結果
繼承Thread類,實現run方法,通過例項的start()方法,告知系統可以開始執行該run方法,根據系統排程器分配執行時間片,進行執行。
多次執行,執行結果不相同。
實現跳舞的執行緒和實現聽歌的執行緒不相同。
例項2(多執行緒與I/O結合:多執行緒實現圖片下載)
public class test11 { public static void main(String[] args){ String url1 = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1540353806265&di=e4258c87892a1b4080891f0d03241a74&imgtype=0&src=http%3A%2F%2Fimg2.dwstatic.com%2Fnews%2F1809%2F401517849603%2F401517880783.jpeg"; String url2 = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1540948740&di=6ec8f3d51fdc501444cd58d47971db87&imgtype=jpg&er=1&src=http%3A%2F%2F07.imgmini.eastday.com%2Fmobile%2F20171102%2F20171102173205_2fb5db37f5a7fcb32d6054adcb21f28a_1.jpeg"; String url3 = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1540354085940&di=2aec582b87582ecb0426bede2462f987&imgtype=0&src=http%3A%2F%2Fpic.anzogame.com%2Flol%2Fnews%2F20140829%2F14092426723701_org.jpg"; MyThread2 dl1 = new MyThread2(url1,"E:/for_file/2.png" ); MyThread2 dl2 = new MyThread2(url2,"E:/for_file/3.png" ); MyThread2 dl3 = new MyThread2(url3,"E:/for_file/4.png" ); dl1.start(); dl2.start(); dl3.start(); } }class Downloadimg{ public void Download(String url, String path){ try { FileUtils.copyURLToFile(new URL(url),new File(path) ); } catch (IOException e) { e.printStackTrace(); } } }class MyThread2 extends Thread{ private String url; private String path; public MyThread2(String url,String path){ this.url = url; this.path = path; } public void run() { Downloadimg dli = new Downloadimg(); dli.Download(this.url,this.path ); } }
引用Commons IO jar包中的方法進行檔案內容的複製,其實變相於下載。
實現runnable介面
class MyThread implements Runnable{ public void run(){ for(int i = 0;i<5;i++){ System.out.println("聽歌"); } } public static void main(String[] args){ //建立實現類物件 MyThread my = new MyThread(); //建立代理類物件 Thread t = new Thread(my); t.start(); for(int i = 0;i<5;i++){ System.out.println("跳舞");//由cpu去調配 } } }
實現介面,重寫run方法,然後建立子類物件和Thread類的代理物件,通過將子類物件以傳參的形式傳給代理物件,通過呼叫代理物件的start()方式進行排程。
如果只執行一次,可以如上進行編碼;
相比較繼承類,推薦實現介面的方法:
1、方便共享資源
2、繼承類單繼承的侷限性
Thread類的原始碼:
引數1:可執行目標
引數2:姓名(給執行緒賦予稱號)
例項:
public class test10 { public static void main(String[] args){ MyThread my = new MyThread(); new Thread(my,"小二").start(); new Thread(my,"小一").start(); } }class MyThread implements Runnable{ private int num = 20; @Override public void run() { while(true){ if(num<0){ break; } System.out.println(Thread.currentThread().getName()+"----"+num--); } } }
單任務多執行緒並給每個執行緒設定名字
執行結果
當一個任務有多個代理共同執行時,如果有網路延遲等問題,會導致併發,這時候就是執行緒不安全,需要進行處理。
實現Callable的Call方法
public class test10 { public static void main(String[] args) { //建立執行服務 MyThread my1 = new MyThread(); MyThread my2 = new MyThread(); ExecutorService es = Executors.newFixedThreadPool(2); //提交執行 Future<String> r1 = es.submit(my1); Future<String> r2 = es.submit(my2); //獲取結果 try { String re1 = r1.get(); System.out.println(re1); String re2 = r2.get(); System.out.println(re2); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } //關閉服務 es.shutdownNow(); } }class MyThread implements Callable<String> { @Override public String call() throws Exception { return "有些失望是不可避免的,但大部分的失望,都因為你高估了自己。"; } }
執行結果
比較複雜,暫時只需要瞭解:
繼承Callable介面,實現call方法,確定返回值型別。
執行操作:
1、建立執行服務 ExecutorService es = Executors.newFixedThreadPool(2);
2、提交任務 Future<String> r1 = es.submit(my1);
3、接受返回值 String r = r1.get();
4、結束服務 es.shutdownNow();