[Java][华为云Java编程创造营][学习笔记][第三阶段][05_Java多线程实战][01_创建线程]
【摘要】 1,创建线程 1.1,进程和线程 进程进程是并发执行程序在执行过程中资源分配和管理的基本单元。进程可以理解为一个应用程序的执行过程,应用程序一旦执行,就是一个进程。 线程线程是进程的一个执行单元,是进程内可调度实体。线程是比进程更小的独立运行的基本单位。线程也被称为轻量级进程。 通俗理解进程和线程:1,启动QQ,开了一个进程;开了迅雷,开了一个进程。在QQ的这个进程里,传输文字开了一个线程...
1,创建线程
1.1,进程和线程
进程
- 进程是并发执行程序在执行过程中资源分配和管理的基本单元。
- 进程可以理解为一个应用程序的执行过程,应用程序一旦执行,就是一个进程。
线程
- 线程是进程的一个执行单元,是进程内可调度实体。
- 线程是比进程更小的独立运行的基本单位。
- 线程也被称为轻量级进程。
通俗理解进程和线程:
- 1,启动QQ,开了一个进程;开了迅雷,开了一个进程。在QQ的这个进程里,传输文字开了一个线程,传输语音开了一个线程。
- 2,通俗说:进程是爹妈,管着众多的线程子女。
进程和线程的区别
名称 | 进程 | 线程 |
---|---|---|
地址空间 | 不同的进程之间的地址空间是独立的 | 同一进程的所有线程共享本进程的地址空间 |
资源拥有 | 进程之间的资源是独立的,无法共享 | 同一进程的所有线程共享本进程的资源 |
执行过程 | 每一个进程可以说就是一个可执行的应用程序 | 线程不能够独立执行,必须依存在应用程序中 |
1.2,创建线程的五种方式
1,继承Thread类
- 通过继承Thread并且重写其run(),run方法中定义需要执行的任务。创建后的子类通过调用start()方法即可执行线程方法。
- 通过继承Thread实现的线程类,多个线程间无法共享线程类的实例变量。需要创建不同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,实现Runnable接口
- 需要先定义一个类实现Runnable接口并重写该接口的run()方法,此run方法是线程执行体。
- 接着创建Runnable实现类的对象,作为创建Thread兑现个参数target,此Thread对象才是真正的线程对象。
- 利用实现Runnable接口的线程类创建对象,可以实现线程之间的资源共享。
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();
/*
* 输出结果
* 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,实现Callable接口
- 实现Callable接口实现带有返回值的线程
- Callable接口如同Runnable接口的升级版,其提供的call()方法将作为线程的执行体,同时允许有返回值。
- 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可以作为实现线程的另一种方式。
- Timer是一种线程设施,用于安排以后在后台线程中执行的任务。可安排任务执行一次,或者定期重复执行,可以看成一个定时器,可以调度TimerTask。
- TimerTask是一个抽象类,实现了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);
/*
* 输出结果
* 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的工具类可以创建线程池。
- 提高系统响应速度,当有任务到达时,通过复用已存在的线程,无需等待新线程的创建便能立即执行。
- 降低系统资源消耗,通过重用已存在的线程,降低线程创建和销毁造成的消耗。
- 方便线程并发数的管控。因为线程若是无限制的创建,可能会导致内存占用过多而产生OOM,并且会造成CPU过度切换。
线程池一:FixThreadPool(int n)固定大小的线程池
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();
/*
* 输出结果
* 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
* */
}
}
线程池二:SingleThreadPoolExecutor单线程池
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();
/*
* 输出结果
* 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
* */
}
}
线程池三:CashedThreadPool()缓存线程池
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();
/*
* 输出结果
* 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
* */
}
}
线程池四:newScheduledThreadPool()创建一个周期性的线程池,支持定时及周期性执行任务
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() + ",执行 " + new Date());
}
}, 1, 3, TimeUnit.SECONDS);
/*
* 输出结果:
* pool-1-thread-1,执行 Tue Dec 14 11:35:55 CST 2021
pool-1-thread-1,执行 Tue Dec 14 11:35:58 CST 2021
pool-1-thread-2,执行 Tue Dec 14 11:36:01 CST 2021
pool-1-thread-1,执行 Tue Dec 14 11:36:04 CST 2021
pool-1-thread-3,执行 Tue Dec 14 11:36:07 CST 2021
pool-1-thread-3,执行 Tue Dec 14 11:36:10 CST 2021
pool-1-thread-4,执行 Tue Dec 14 11:36:13 CST 2021
pool-1-thread-4,执行 Tue Dec 14 11:36:16 CST 2021
* */
}
}
线程池五:newWorkStealingPool新的线程池类ForkJoinPool的扩展
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);//让主线程等待子线程执行完毕,也可以使用计数器方式
System.out.println("---end---");
/*
* 输出结果
* ---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接口区别
继承Thread类实现卖票操作
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();
}
/*
* 输出结果
* 一号窗口卖出第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票
* */
}
实现Runnable接口实现卖票操作
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();
}
}
/*
* 输出结果
* 一号窗口卖出第1票
一号窗口卖出第4票
一号窗口卖出第5票
一号窗口卖出第6票
一号窗口卖出第7票
一号窗口卖出第8票
一号窗口卖出第9票
一号窗口卖出第10票
三号窗口卖出第3票
二号窗口卖出第2票
* */
1.4,线程start和run方法的区别
线程对象调用run方法案例
class UserThread extends Thread
{
public void run()
{
System.out.println(Thread.currentThread().getName() + ",执行run方法");
}
}
public class Demo12
{
public static void main(String[] args)
{
System.out.println(Thread.currentThread().getName() + ",执行main方法");
UserThread userThread = new UserThread();
userThread.run();
/*
* 输出结果
* main,执行main方法
main,执行run方法
* */
}
}
线程对象使用start()方法案例
class UserThread extends Thread
{
public void run()
{
System.out.println(Thread.currentThread().getName() + ",执行run方法");
}
}
public class Demo13
{
public static void main(String[] args)
{
System.out.println(Thread.currentThread().getName() + ",执行main方法");
UserThread userThread = new UserThread();
userThread.start();
/*
* 输出结果
* main,执行main方法
Thread-0,执行run方法
* */
}
}
1.5,线程的优先级
- Java线程的优先级范围是1-10,默认优先级是5,10最高。
- 线程的优先级仍然无法保障线程的执行次序。
- 优先级高的线程获取CPU资源的概率较大,优先级低的并非没机会执行。
- 主线程main的优先级是5.
Java线程的优先级案例
class UserThread extends Thread
{
public void run()
{
for (int i = 0; i < 10; i++)
{
System.out.println(Thread.currentThread().getName() + "第" + i + "次执行!");
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 + "次执行!");
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执行结果
* Thread-0第0次执行!
Thread-0第1次执行!
Thread-0第2次执行!
Thread-0第3次执行!
Thread-0第4次执行!
Thread-0第5次执行!
Thread-0第6次执行!
Thread-0第7次执行!
Thread-0第8次执行!
Thread-0第9次执行!
* */
/*
* t2执行结果
* Thread-1,第0次执行!
Thread-1,第1次执行!
Thread-1,第2次执行!
Thread-1,第3次执行!
Thread-1,第4次执行!
Thread-1,第5次执行!
Thread-1,第6次执行!
Thread-1,第7次执行!
Thread-1,第8次执行!
Thread-1,第9次执行!
* */
}
}
1.6,定时线程的任务调度
定时线程Schedule():延时不追加执行任务
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);
/*
* 输出结果
* Timer-0,Tue Dec 14 21:48:23 CST 2021
* */
}
}
定时线程scheduleAtFixedRate():延时追加执行任务
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);
/*
* 输出结果
* Timer-0,Tue Dec 14 21:40:32 CST 2021
Timer-0,Tue Dec 14 21:40:32 CST 2021
* */
}
}
1.7,接口同步回调和异步回调
-
同步调用
- 一种阻塞式调用,调用方要等待对方执行完毕才返回,它是一种单向调用。
-
回调
- 一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口。
-
异步调用
- 一种类似消息或事件的机制,不过它的调用方向刚好相反,接口的服务在收到某种讯息或发生某种事件时,会主动通知客户方。
-
接口同步回调案例
interface Callback
{
public void process(int status);
}
class MyCallback implements Callback
{
@Override
public void process(int status)
{
System.out.println("处理成功,返回状态为:" + status);
}
}
class Server
{
public void getMsg(Callback callback, String msg) throws InterruptedException
{
System.out.println("服务端获得消息:" + msg);
//模拟处理消息过程,等待两秒
Thread.sleep(2000);
System.out.println("服务端处理成功,返回状态为200");
//处理完消息,调用回调方法,告知客户端
callback.process(200);
}
}
class Client
{
Server server;
public Client(Server server)
{
this.server = server;
}
public void sendMsg(final String msg)
{
System.out.println("客户端正在发送消息:" + msg);
try
{
server.getMsg(new MyCallback(), msg);
} catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println("客户端已经发送消息给服务器了,请稍等");
}
}
/*
* 接口同步回调案例
* */
public class Demo17
{
public static void main(String[] args)
{
Server server = new Server();
Client client = new Client(server);
client.sendMsg("我要充值");
/*
* 输出结果
* 客户端正在发送消息:我要充值
服务端获得消息:我要充值
服务端处理成功,返回状态为200
处理成功,返回状态为:200
客户端已经发送消息给服务器了,请稍等
* */
}
}
- 接口异步调用案例
interface Callback
{
public void process(int status);
}
class MyCallback implements Callback
{
@Override
public void process(int status)
{
System.out.println("处理成功,返回状态为:" + status);
}
}
class Server
{
public void getMsg(Callback callback, String msg) throws InterruptedException
{
System.out.println("服务端获得消息:" + msg);
//模拟处理消息过程,等待两秒
Thread.sleep(2000);
System.out.println("服务端处理成功,返回状态为200");
//处理完消息,调用回调方法,告知客户端
callback.process(200);
}
}
class Client
{
Server server;
public Client(Server server)
{
this.server = server;
}
public void sendMsg(final String msg)
{
System.out.println("客户端正在发送消息:" + msg);
new Thread(new Runnable()
{
@Override
public void run()
{
try
{
//调用server类的获取消息方法,并且传入mycallback对象
server.getMsg(new MyCallback(), msg);
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
}).start();
System.out.println("客户端已经发送消息给服务器了,请稍等");
}
}
public class Demo18
{
public static void main(String[] args)
{
Server server = new Server();
Client client = new Client(server);
client.sendMsg("我要充值");
/*
* 输出结果
* 客户端正在发送消息:我要充值
客户端已经发送消息给服务器了,请稍等
服务端获得消息:我要充值
服务端处理成功,返回状态为200
处理成功,返回状态为:200
* */
}
}
- 回调分为同步和异步,区别就是需不需要等待服务器端的返回结果
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)