[Java][華為云Java編程創(chuàng)造營][學習筆記][第三階段][05_Java多線程實戰(zhàn)][01_創(chuàng)建線程]

      網(wǎng)友投稿 606 2025-04-07

      1,創(chuàng)建線程


      1.1,進程和線程

      進程

      [Java][華為云Java編程創(chuàng)造營][學習筆記][第三階段][05_Java多線程實戰(zhàn)][01_創(chuàng)建線程]

      進程是并發(fā)執(zhí)行程序在執(zhí)行過程中資源分配和管理的基本單元。

      進程可以理解為一個應用程序的執(zhí)行過程,應用程序一旦執(zhí)行,就是一個進程。

      線程

      線程是進程的一個執(zhí)行單元,是進程內(nèi)可調(diào)度實體。

      線程是比進程更小的獨立運行的基本單位。

      線程也被稱為輕量級進程。

      通俗理解進程和線程:

      1,啟動QQ,開了一個進程;開了迅雷,開了一個進程。在QQ的這個進程里,傳輸文字開了一個線程,傳輸語音開了一個線程。

      2,通俗說:進程是爹媽,管著眾多的線程子女。

      進程和線程的區(qū)別

      1.2,創(chuàng)建線程的五種方式

      1,繼承Thread類

      通過繼承Thread并且重寫其run(),run方法中定義需要執(zhí)行的任務。創(chuàng)建后的子類通過調(diào)用start()方法即可執(zhí)行線程方法。

      通過繼承Thread實現(xiàn)的線程類,多個線程間無法共享線程類的實例變量。需要創(chuàng)建不同Thread對象,自然不共享資源。

      class UserThread extends Thread { @Override public void run() { for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + " is running " + i); } } } public class Demo1 { public static void main(String[] args) { for (int i = 0; i < 2; i++) { new UserThread().start(); } /* * Thread-1 is running 0 Thread-1 is running 1 Thread-1 is running 2 Thread-1 is running 3 Thread-1 is running 4 Thread-0 is running 0 Thread-0 is running 1 Thread-0 is running 2 Thread-0 is running 3 Thread-0 is running 4 * */ } }

      2,實現(xiàn)Runnable接口

      需要先定義一個類實現(xiàn)Runnable接口并重寫該接口的run()方法,此run方法是線程執(zhí)行體。

      接著創(chuàng)建Runnable實現(xiàn)類的對象,作為創(chuàng)建Thread兌現(xiàn)個參數(shù)target,此Thread對象才是真正的線程對象。

      利用實現(xiàn)Runnable接口的線程類創(chuàng)建對象,可以實現(xiàn)線程之間的資源共享。

      class UserRunn implements Runnable { @Override public void run() { for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + " is running " + i); } } } public class Demo2 { public static void main(String[] args) { UserRunn runn = new UserRunn(); new Thread(runn).start(); new Thread(runn).start(); /* * 輸出結(jié)果 * Thread-0 is running 0 Thread-0 is running 1 Thread-0 is running 2 Thread-0 is running 3 Thread-0 is running 4 Thread-1 is running 0 Thread-1 is running 1 Thread-1 is running 2 Thread-1 is running 3 Thread-1 is running 4 * */ } }

      ,3,實現(xiàn)Callable接口

      實現(xiàn)Callable接口實現(xiàn)帶有返回值的線程

      Callable接口如同Runnable接口的升級版,其提供的call()方法將作為線程的執(zhí)行體,同時允許有返回值。

      Callable對象不能直接作為Thread對象的target,因為Callable接口是Java5新增的接口,不是Runnable接口的子接口。

      對于這個問題的解決方案,就引入Future接口,此接口可以接受call()的返回值,RunnableFuture接口是Future接口和Runnable接口的子接口,可以作為Thread對象的target。

      import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; class UserCallable implements Callable { @Override public Object call() throws Exception { return "hello"; } } public class Demo3 { public static void main(String[] args) throws ExecutionException, InterruptedException { UserCallable userCallable = new UserCallable(); FutureTask futureTask = new FutureTask(userCallable); Thread t = new Thread(futureTask); t.start(); System.out.println(futureTask.get());//hello } }

      ,4,繼承TimerTask

      Timer和TimerTask可以作為實現(xiàn)線程的另一種方式。

      Timer是一種線程設(shè)施,用于安排以后在后臺線程中執(zhí)行的任務。可安排任務執(zhí)行一次,或者定期重復執(zhí)行,可以看成一個定時器,可以調(diào)度TimerTask。

      TimerTask是一個抽象類,實現(xiàn)了Runnable接口,所以具備了多線程能力。

      import java.util.Date; import java.util.Timer; import java.util.TimerTask; class UserTask extends TimerTask { @Override public void run() { System.out.println(Thread.currentThread().getName() + " is running " + new Date()); } } public class Demo4 { public static void main(String[] args) { Timer timer = new Timer(); timer.schedule(new UserTask(), 2000, 3000); /* * 輸出結(jié)果 * Timer-0 is running Wed Dec 08 15:46:39 CST 2021 Timer-0 is running Wed Dec 08 15:46:42 CST 2021 Timer-0 is running Wed Dec 08 15:46:45 CST 2021 Timer-0 is running Wed Dec 08 15:46:48 CST 2021 Timer-0 is running Wed Dec 08 15:46:51 CST 2021 Timer-0 is running Wed Dec 08 15:46:54 CST 2021 Timer-0 is running Wed Dec 08 15:46:57 CST 2021 Timer-0 is running Wed Dec 08 15:47:00 CST 2021 Timer-0 is running Wed Dec 08 15:47:03 CST 2021 Timer-0 is running Wed Dec 08 15:47:06 CST 2021 Timer-0 is running Wed Dec 08 15:47:09 CST 2021 Timer-0 is running Wed Dec 08 15:47:12 CST 2021 Timer-0 is running Wed Dec 08 15:47:15 CST 2021 Timer-0 is running Wed Dec 08 15:47:18 CST 2021 * */ } }

      5,通過線程池啟動多線程

      通過Executors的工具類可以創(chuàng)建線程池。

      提高系統(tǒng)響應速度,當有任務到達時,通過復用已存在的線程,無需等待新線程的創(chuàng)建便能立即執(zhí)行。

      降低系統(tǒng)資源消耗,通過重用已存在的線程,降低線程創(chuàng)建和銷毀造成的消耗。

      方便線程并發(fā)數(shù)的管控。因為線程若是無限制的創(chuàng)建,可能會導致內(nèi)存占用過多而產(chǎn)生OOM,并且會造成CPU過度切換。

      import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Demo5 { public static void main(String[] args) { ExecutorService ex = Executors.newFixedThreadPool(3); for (int i = 0; i < 5; i++) { ex.submit(new Runnable() { @Override public void run() { for (int j = 0; j < 10; j++) { System.out.println(Thread.currentThread().getName() + " " + j); } } }); } ex.shutdown(); /* * 輸出結(jié)果 * pool-1-thread-2 0 pool-1-thread-2 1 pool-1-thread-2 2 pool-1-thread-2 3 pool-1-thread-2 4 pool-1-thread-2 5 pool-1-thread-2 6 pool-1-thread-2 7 pool-1-thread-2 8 pool-1-thread-2 9 pool-1-thread-2 0 pool-1-thread-2 1 pool-1-thread-2 2 pool-1-thread-2 3 pool-1-thread-2 4 pool-1-thread-2 5 pool-1-thread-2 6 pool-1-thread-2 7 pool-1-thread-2 8 pool-1-thread-2 9 pool-1-thread-2 0 pool-1-thread-2 1 pool-1-thread-2 2 pool-1-thread-2 3 pool-1-thread-2 4 pool-1-thread-2 5 pool-1-thread-2 6 pool-1-thread-2 7 pool-1-thread-2 8 pool-1-thread-2 9 pool-1-thread-1 0 pool-1-thread-1 1 pool-1-thread-1 2 pool-1-thread-1 3 pool-1-thread-1 4 pool-1-thread-1 5 pool-1-thread-1 6 pool-1-thread-1 7 pool-1-thread-1 8 pool-1-thread-1 9 pool-1-thread-3 0 pool-1-thread-3 1 pool-1-thread-3 2 pool-1-thread-3 3 pool-1-thread-3 4 pool-1-thread-3 5 pool-1-thread-3 6 pool-1-thread-3 7 pool-1-thread-3 8 pool-1-thread-3 9 * */ } }

      import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Demo6 { public static void main(String[] args) { ExecutorService ex = Executors.newSingleThreadExecutor(); for (int i = 0; i < 5; i++) { ex.submit(new Runnable() { @Override public void run() { for (int j = 0; j < 10; j++) { System.out.println(Thread.currentThread().getName() + " " + j); } } }); } ex.shutdown(); /* * 輸出結(jié)果 * pool-1-thread-1 0 pool-1-thread-1 1 pool-1-thread-1 2 pool-1-thread-1 3 pool-1-thread-1 4 pool-1-thread-1 5 pool-1-thread-1 6 pool-1-thread-1 7 pool-1-thread-1 8 pool-1-thread-1 9 pool-1-thread-1 0 pool-1-thread-1 1 pool-1-thread-1 2 pool-1-thread-1 3 pool-1-thread-1 4 pool-1-thread-1 5 pool-1-thread-1 6 pool-1-thread-1 7 pool-1-thread-1 8 pool-1-thread-1 9 pool-1-thread-1 0 pool-1-thread-1 1 pool-1-thread-1 2 pool-1-thread-1 3 pool-1-thread-1 4 pool-1-thread-1 5 pool-1-thread-1 6 pool-1-thread-1 7 pool-1-thread-1 8 pool-1-thread-1 9 pool-1-thread-1 0 pool-1-thread-1 1 pool-1-thread-1 2 pool-1-thread-1 3 pool-1-thread-1 4 pool-1-thread-1 5 pool-1-thread-1 6 pool-1-thread-1 7 pool-1-thread-1 8 pool-1-thread-1 9 pool-1-thread-1 0 pool-1-thread-1 1 pool-1-thread-1 2 pool-1-thread-1 3 pool-1-thread-1 4 pool-1-thread-1 5 pool-1-thread-1 6 pool-1-thread-1 7 pool-1-thread-1 8 pool-1-thread-1 9 * */ } }

      import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Demo7 { public static void main(String[] args) { ExecutorService ex = Executors.newCachedThreadPool(); for (int i = 0; i < 5; i++) { ex.submit(new Runnable() { @Override public void run() { for (int j = 0; j < 10; j++) { System.out.println(Thread.currentThread().getName() + " " + j); } } }); } ex.shutdown(); /* * 輸出結(jié)果 * pool-1-thread-1 0 pool-1-thread-2 0 pool-1-thread-2 1 pool-1-thread-2 2 pool-1-thread-4 0 pool-1-thread-4 1 pool-1-thread-4 2 pool-1-thread-4 3 pool-1-thread-4 4 pool-1-thread-4 5 pool-1-thread-4 6 pool-1-thread-4 7 pool-1-thread-4 8 pool-1-thread-4 9 pool-1-thread-1 1 pool-1-thread-1 2 pool-1-thread-1 3 pool-1-thread-1 4 pool-1-thread-1 5 pool-1-thread-1 6 pool-1-thread-1 7 pool-1-thread-1 8 pool-1-thread-1 9 pool-1-thread-3 0 pool-1-thread-5 0 pool-1-thread-2 3 pool-1-thread-2 4 pool-1-thread-2 5 pool-1-thread-2 6 pool-1-thread-5 1 pool-1-thread-3 1 pool-1-thread-3 2 pool-1-thread-3 3 pool-1-thread-5 2 pool-1-thread-5 3 pool-1-thread-5 4 pool-1-thread-5 5 pool-1-thread-5 6 pool-1-thread-5 7 pool-1-thread-5 8 pool-1-thread-5 9 pool-1-thread-2 7 pool-1-thread-3 4 pool-1-thread-3 5 pool-1-thread-3 6 pool-1-thread-3 7 pool-1-thread-3 8 pool-1-thread-3 9 pool-1-thread-2 8 pool-1-thread-2 9 * */ } }

      import java.util.Date; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class Demo8 { public static void main(String[] args) { ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5); scheduledThreadPool.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + ",執(zhí)行 " + new Date()); } }, 1, 3, TimeUnit.SECONDS); /* * 輸出結(jié)果: * pool-1-thread-1,執(zhí)行 Tue Dec 14 11:35:55 CST 2021 pool-1-thread-1,執(zhí)行 Tue Dec 14 11:35:58 CST 2021 pool-1-thread-2,執(zhí)行 Tue Dec 14 11:36:01 CST 2021 pool-1-thread-1,執(zhí)行 Tue Dec 14 11:36:04 CST 2021 pool-1-thread-3,執(zhí)行 Tue Dec 14 11:36:07 CST 2021 pool-1-thread-3,執(zhí)行 Tue Dec 14 11:36:10 CST 2021 pool-1-thread-4,執(zhí)行 Tue Dec 14 11:36:13 CST 2021 pool-1-thread-4,執(zhí)行 Tue Dec 14 11:36:16 CST 2021 * */ } }

      import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Demo9 { public static void main(String[] args) throws InterruptedException { System.out.println("---start---"); ExecutorService executorService = Executors.newWorkStealingPool(); for (int i = 0; i < 10; i++) { executorService.submit(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()); } }); } Thread.sleep(3000);//讓主線程等待子線程執(zhí)行完畢,也可以使用計數(shù)器方式 System.out.println("---end---"); /* * 輸出結(jié)果 * ---start--- ForkJoinPool-1-worker-1 ForkJoinPool-1-worker-1 ForkJoinPool-1-worker-1 ForkJoinPool-1-worker-1 ForkJoinPool-1-worker-1 ForkJoinPool-1-worker-1 ForkJoinPool-1-worker-1 ForkJoinPool-1-worker-1 ForkJoinPool-1-worker-1 ForkJoinPool-1-worker-1 ---end--- * */ } }

      1.3,Thread類和Runnable接口區(qū)別

      繼承Thread類實現(xiàn)賣票操作

      class MyThread extends Thread { private int ticket = 10; private String name; public MyThread(String name) { this.name = name; } public void run() { for (int i = 0; i < 500; i++) { if (this.ticket > 0) { System.out.println(this.name + "賣出第" + (10 - this.ticket-- + 1) + "票"); } } } } public class Demo10 { public static void main(String[] args) { MyThread mt1 = new MyThread("一號窗口"); MyThread mt2 = new MyThread("二號窗口"); MyThread mt3 = new MyThread("三號窗口"); mt1.start(); mt2.start(); mt3.start(); } /* * 輸出結(jié)果 * 一號窗口賣出第1票 三號窗口賣出第1票 三號窗口賣出第2票 三號窗口賣出第3票 三號窗口賣出第4票 三號窗口賣出第5票 三號窗口賣出第6票 三號窗口賣出第7票 三號窗口賣出第8票 三號窗口賣出第9票 三號窗口賣出第10票 二號窗口賣出第1票 二號窗口賣出第2票 二號窗口賣出第3票 一號窗口賣出第2票 二號窗口賣出第4票 二號窗口賣出第5票 二號窗口賣出第6票 二號窗口賣出第7票 二號窗口賣出第8票 二號窗口賣出第9票 二號窗口賣出第10票 一號窗口賣出第3票 一號窗口賣出第4票 一號窗口賣出第5票 一號窗口賣出第6票 一號窗口賣出第7票 一號窗口賣出第8票 一號窗口賣出第9票 一號窗口賣出第10票 * */ }

      實現(xiàn)Runnable接口實現(xiàn)賣票操作

      class MyThread implements Runnable { private int ticket = 10; @Override public void run() { for (int i = 0; i < 500; i++) { if (this.ticket > 0) { System.out.println(Thread.currentThread().getName() + "賣出第" + (10 - this.ticket-- + 1) + "票"); } } } } public class Demo11 { public static void main(String[] args) { MyThread mt = new MyThread(); Thread t1 = new Thread(mt, "一號窗口"); Thread t2 = new Thread(mt, "二號窗口"); Thread t3 = new Thread(mt, "三號窗口"); t1.start(); t2.start(); t3.start(); } } /* * 輸出結(jié)果 * 一號窗口賣出第1票 一號窗口賣出第4票 一號窗口賣出第5票 一號窗口賣出第6票 一號窗口賣出第7票 一號窗口賣出第8票 一號窗口賣出第9票 一號窗口賣出第10票 三號窗口賣出第3票 二號窗口賣出第2票 * */

      1.4,線程start和run方法的區(qū)別

      線程對象調(diào)用run方法案例

      class UserThread extends Thread { public void run() { System.out.println(Thread.currentThread().getName() + ",執(zhí)行run方法"); } } public class Demo12 { public static void main(String[] args) { System.out.println(Thread.currentThread().getName() + ",執(zhí)行main方法"); UserThread userThread = new UserThread(); userThread.run(); /* * 輸出結(jié)果 * main,執(zhí)行main方法 main,執(zhí)行run方法 * */ } }

      線程對象使用start()方法案例

      class UserThread extends Thread { public void run() { System.out.println(Thread.currentThread().getName() + ",執(zhí)行run方法"); } } public class Demo13 { public static void main(String[] args) { System.out.println(Thread.currentThread().getName() + ",執(zhí)行main方法"); UserThread userThread = new UserThread(); userThread.start(); /* * 輸出結(jié)果 * main,執(zhí)行main方法 Thread-0,執(zhí)行run方法 * */ } }

      1.5,線程的優(yōu)先級

      Java線程的優(yōu)先級范圍是1-10,默認優(yōu)先級是5,10最高。

      線程的優(yōu)先級仍然無法保障線程的執(zhí)行次序。

      優(yōu)先級高的線程獲取CPU資源的概率較大,優(yōu)先級低的并非沒機會執(zhí)行。

      主線程main的優(yōu)先級是5.

      Java線程的優(yōu)先級案例

      class UserThread extends Thread { public void run() { for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName() + "第" + i + "次執(zhí)行!"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } class UserRunn implements Runnable { @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName() + ",第" + i + "次執(zhí)行!"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } public class Demo14 { public static void main(String[] args) { Thread t1 = new UserThread(); Thread t2 = new Thread(new UserRunn()); //t1.setPriority(10); t2.setPriority(1); t2.start(); //t1.start(); /* * t1執(zhí)行結(jié)果 * Thread-0第0次執(zhí)行! Thread-0第1次執(zhí)行! Thread-0第2次執(zhí)行! Thread-0第3次執(zhí)行! Thread-0第4次執(zhí)行! Thread-0第5次執(zhí)行! Thread-0第6次執(zhí)行! Thread-0第7次執(zhí)行! Thread-0第8次執(zhí)行! Thread-0第9次執(zhí)行! * */ /* * t2執(zhí)行結(jié)果 * Thread-1,第0次執(zhí)行! Thread-1,第1次執(zhí)行! Thread-1,第2次執(zhí)行! Thread-1,第3次執(zhí)行! Thread-1,第4次執(zhí)行! Thread-1,第5次執(zhí)行! Thread-1,第6次執(zhí)行! Thread-1,第7次執(zhí)行! Thread-1,第8次執(zhí)行! Thread-1,第9次執(zhí)行! * */ } }

      1.6,定時線程的任務調(diào)度

      定時線程Schedule():延時不追加執(zhí)行任務

      import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Timer; import java.util.TimerTask; class UserTask extends TimerTask { @Override public void run() { System.out.println(Thread.currentThread().getName() + "," + new Date()); } } public class Demo15 { public static void main(String[] args) { Timer t = new Timer(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); Date date = null; try { date = sdf.parse("2021-12-14 00:00:00"); } catch (ParseException e) { e.printStackTrace(); } t.schedule(new UserTask(), date, 3 * 60 * 1000); /* * 輸出結(jié)果 * Timer-0,Tue Dec 14 21:48:23 CST 2021 * */ } }

      定時線程scheduleAtFixedRate():延時追加執(zhí)行任務

      import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Timer; import java.util.TimerTask; class UserTask extends TimerTask { @Override public void run() { System.out.println(Thread.currentThread().getName() + "," + new Date()); } } public class Demo16 { public static void main(String[] args) { Timer t = new Timer(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); Date date = null; try { date = sdf.parse("2021-12-14 05:00:00"); } catch (ParseException e) { e.printStackTrace(); } t.scheduleAtFixedRate(new UserTask(), date, 3 * 60 * 1000); /* * 輸出結(jié)果 * Timer-0,Tue Dec 14 21:40:32 CST 2021 Timer-0,Tue Dec 14 21:40:32 CST 2021 * */ } }

      1.7,接口同步回調(diào)和異步回調(diào)

      同步調(diào)用

      一種阻塞式調(diào)用,調(diào)用方要等待對方執(zhí)行完畢才返回,它是一種單向調(diào)用。

      回調(diào)

      一種雙向調(diào)用模式,也就是說,被調(diào)用方在接口被調(diào)用時也會調(diào)用對方的接口。

      異步調(diào)用

      一種類似消息或事件的機制,不過它的調(diào)用方向剛好相反,接口的服務在收到某種訊息或發(fā)生某種事件時,會主動通知客戶方。

      接口同步回調(diào)案例

      interface Callback { public void process(int status); } class MyCallback implements Callback { @Override public void process(int status) { System.out.println("處理成功,返回狀態(tài)為:" + status); } } class Server { public void getMsg(Callback callback, String msg) throws InterruptedException { System.out.println("服務端獲得消息:" + msg); //模擬處理消息過程,等待兩秒 Thread.sleep(2000); System.out.println("服務端處理成功,返回狀態(tài)為200"); //處理完消息,調(diào)用回調(diào)方法,告知客戶端 callback.process(200); } } class Client { Server server; public Client(Server server) { this.server = server; } public void sendMsg(final String msg) { System.out.println("客戶端正在發(fā)送消息:" + msg); try { server.getMsg(new MyCallback(), msg); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("客戶端已經(jīng)發(fā)送消息給服務器了,請稍等"); } } /* * 接口同步回調(diào)案例 * */ public class Demo17 { public static void main(String[] args) { Server server = new Server(); Client client = new Client(server); client.sendMsg("我要充值"); /* * 輸出結(jié)果 * 客戶端正在發(fā)送消息:我要充值 服務端獲得消息:我要充值 服務端處理成功,返回狀態(tài)為200 處理成功,返回狀態(tài)為:200 客戶端已經(jīng)發(fā)送消息給服務器了,請稍等 * */ } }

      接口異步調(diào)用案例

      interface Callback { public void process(int status); } class MyCallback implements Callback { @Override public void process(int status) { System.out.println("處理成功,返回狀態(tài)為:" + status); } } class Server { public void getMsg(Callback callback, String msg) throws InterruptedException { System.out.println("服務端獲得消息:" + msg); //模擬處理消息過程,等待兩秒 Thread.sleep(2000); System.out.println("服務端處理成功,返回狀態(tài)為200"); //處理完消息,調(diào)用回調(diào)方法,告知客戶端 callback.process(200); } } class Client { Server server; public Client(Server server) { this.server = server; } public void sendMsg(final String msg) { System.out.println("客戶端正在發(fā)送消息:" + msg); new Thread(new Runnable() { @Override public void run() { try { //調(diào)用server類的獲取消息方法,并且傳入mycallback對象 server.getMsg(new MyCallback(), msg); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); System.out.println("客戶端已經(jīng)發(fā)送消息給服務器了,請稍等"); } } public class Demo18 { public static void main(String[] args) { Server server = new Server(); Client client = new Client(server); client.sendMsg("我要充值"); /* * 輸出結(jié)果 * 客戶端正在發(fā)送消息:我要充值 客戶端已經(jīng)發(fā)送消息給服務器了,請稍等 服務端獲得消息:我要充值 服務端處理成功,返回狀態(tài)為200 處理成功,返回狀態(tài)為:200 * */ } }

      回調(diào)分為同步和異步,區(qū)別就是需不需要等待服務器端的返回結(jié)果

      Java 多線程

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔相應法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔相應法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:EXCEL怎么刪除多列的步驟
      下一篇:wps線條怎么畫?
      相關(guān)文章
      中文字幕亚洲情99在线| 亚洲最大的成人网站| 亚洲AV无码一区二区三区在线| 亚洲精品无码激情AV| 亚洲色大18成人网站WWW在线播放 亚洲色大成WWW亚洲女子 | 亚洲真人无码永久在线| 亚洲日韩小电影在线观看| 亚洲黄片毛片在线观看| 亚洲国产午夜福利在线播放| 亚洲国产欧洲综合997久久| 亚洲高清一区二区三区| 久久亚洲精品国产精品婷婷 | 亚洲国产黄在线观看| 国产亚洲精品91| 亚洲AV无码片一区二区三区| 亚洲欧美日本韩国| 亚洲kkk4444在线观看| 亚洲一卡二卡三卡四卡无卡麻豆| 久久久久久a亚洲欧洲AV| 久久亚洲精品中文字幕无码| 亚洲AV福利天堂一区二区三| 亚洲bt加勒比一区二区| 亚洲国产精品久久久久婷婷老年| 亚洲高清在线播放| 亚洲高清在线mv| 亚洲人成影院77777| 亚洲熟女综合色一区二区三区| 亚洲男人的天堂网站| 亚洲av色香蕉一区二区三区| 亚洲av色香蕉一区二区三区| 内射无码专区久久亚洲| 亚洲免费日韩无码系列| 亚洲综合无码AV一区二区| 亚洲精品乱码久久久久久按摩| 亚洲欧洲∨国产一区二区三区| 国产亚洲3p无码一区二区| 国产综合精品久久亚洲| 亚洲av无码专区国产乱码在线观看| 亚洲avav天堂av在线不卡| 亚洲国产一区国产亚洲| 亚洲国产日韩在线成人蜜芽 |