Java --> 多线程2
- 线程通信
- 案例:加入有一个场景,小明、和小红有3个爸爸,爸爸们负责存钱,小明和小红负责取钱,必须一存、一取。
线程通信的前提:线程通信通常是在多个线程操作同一个共享资源的时候需要进行通信,且要保证线程安全。
1 public class Account {
2 private String cardId;
3 private double money;
4
5 public Account() {
6 }
7
8 //逻辑:消费者要等生产者生产完后才能消费
9 public synchronized void drawMoney(double money){
10 String name = Thread.currentThread().getName();
11 if (this.money >= money){
12 //钱够,可取
13 //更新余额
14 this.money -= money;
15 System.out.println(name + "取了" + money + ",余额为:" + this.money);
16 try {
17 this.notifyAll(); //唤醒所有的线程
18 this.wait(); //锁对象,让当前线程进入等待
19 } catch (Exception e) {
20 e.printStackTrace();
21 }
22 }else {
23 //钱不够,不可取钱
24 //唤醒别人,等待自己
25 try {
26 this.notifyAll(); //唤醒所有线程【先唤醒、在等待,否则:自己等待时其它线程不能跑】
27 this.wait(); //锁对象,用当前线程进入等待
28 } catch (Exception e) {
29 e.printStackTrace();
30 }
31
32 }
33 }
34
35 public Account(String cardId, double money) {
36 this.cardId = cardId;
37 this.money = money;
38 }
39
40 public String getCardId() {
41 return cardId;
42 }
43
44 public void setCardId(String cardId) {
45 this.cardId = cardId;
46 }
47
48 public double getMoney() {
49 return money;
50 }
51
52 public void setMoney(double money) {
53 this.money = money;
54 }
55
56 //逻辑:生产者生产完毕后等消费者消费后在生产
57 public synchronized void deposit(double money) {
58 try {
59 String name = Thread.currentThread().getName();
60 if (this.money == 0){
61 this.money += money;
62 System.out.println(name + "存款:" + money + ",账户余额:" + this.money);
63 //有钱了,唤醒别人,等待自己
64 this.notifyAll();
65 this.wait();
66 }else {
67 this.notifyAll();
68 this.wait();
69 }
70 } catch (Exception e) {
71 e.printStackTrace();
72 }
73 }
74 }
1 //存钱线程类
2 public class DepositThread extends Thread{
3 //定义账户对象
4 private Account account;
5 public DepositThread(Account account, String name){
6 super(name);
7 this.account = account;
8 }
9 @Override
10 public void run() {
11 //取钱【小明、小红】不断地取钱
12 while (true) {
13 try {
14 Thread.sleep(3000);
15 } catch (Exception e) {
16 e.printStackTrace();
17 }
18 account.deposit(100000);
19 }
20 }
21 }
1 //取钱线程类
2 public class DrawThread extends Thread{
3 //定义账户对象
4 private Account account;
5 public DrawThread(Account account, String name){
6 super(name);
7 this.account = account;
8 }
9 @Override
10 public void run() {
11 //取钱【小明、小红】不断地取钱
12 while (true) {
13 try {
14 Thread.sleep(3000);
15 } catch (InterruptedException e) {
16 e.printStackTrace();
17 }
18 account.drawMoney(100000);
19 }
20 }
21 }
1 //了解线程通信的流程
2 public class ThreadDemo {
3 public static void main(String[] args) {
4 //1、使用3个线程【爸爸】存钱,2个取钱,模拟线程通信的思想
5 Account account = new Account("ABC-153675",0);
6
7 //2、创建2个线程代表小明和小红
8 new DrawThread(account,"小明").start();
9 new DrawThread(account,"小红").start();
10 //3、创建3个存钱线程代表 :亲爹、干爹、岳父
11 new DepositThread(account,"亲爹").start();
12 new DepositThread(account,"干爹").start();
13 new DepositThread(account,"岳父").start();
14 }
15 }
示例程序运行结果:
- 线程池处理Runnable、Callable任务
Runnable任务:
1 //自定义Runnable类实现Runnable接口
2 public class MyRunnable implements Runnable {
3 @Override
4 public void run() {
5 for (int i = 0; i < 5; i++) {
6 System.out.println(Thread.currentThread().getName() + "输出了:HelloWorld --> " + i);
7 }
8 try {
9 System.out.println(Thread.currentThread().getName() + "本任务与线程绑定,线程进入休眠");
10 Thread.sleep(100000);
11 } catch (Exception e) {
12 e.printStackTrace();
13 }
14 }
15 }
1 //自定义线程池并定义其特性
2 public class ThreadPoolDemo1 {
3 public static void main(String[] args) {
4 //1、创建线程池对象【多态】
5 /*
6 public ThreadPoolExecutor(int corePoolSize, 核心线程数量【长工】
7 int maximumPoolSize, 最大线程数量【临时工、短工】
8 long keepAliveTime, 最大存活时间
9 TimeUnit unit, 时间单位
10 BlockingQueue<Runnable> workQueue, 任务阻塞队列在此缓存
11 ThreadFactory threadFactory, 线程工厂:创建线程
12 RejectedExecutionHandler handler) 任务的拒绝策略
13 */
14 ExecutorService pool = new ThreadPoolExecutor(3,5,6, TimeUnit.SECONDS,
15 new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(),
16 new ThreadPoolExecutor.AbortPolicy());
17
18 //2、给任务线程池处理
19 Runnable target = new MyRunnable();
20 pool.execute(target);
21 pool.execute(target);
22 pool.execute(target);
23
24 pool.execute(target);
25 pool.execute(target);
26 pool.execute(target);
27 pool.execute(target);
28 pool.execute(target);
29
30 //创建临时线程
31 pool.execute(target);
32 pool.execute(target); //最多可处理10个线程
33
34 //不创建:拒绝策略被触发
35 //pool.execute(target);
36
37 //关闭线程【开发中一般不会使用】
38 //pool.shutdownNow(); //立即关闭,即使任务没有完成,会丢失任务的
39 //pool.shutdown(); //等待全部任务执行完后在关闭
Callable任务:
1 import java.util.concurrent.Callable;
2
3 //定义任务类,实现Callable接口【传入参数n用于】
4 public class MyCallable implements Callable<String> {
5 private int n;
6
7 public MyCallable(int n) {
8 this.n = n;
9 }
10
11 @Override
12 public String call() throws Exception {
13 int sum = 0;
14 for (int i = 1; i <= n; i++) {
15 sum += i;
16 }
17 return Thread.currentThread().getName() + "执行1 ~ " + n + " 的结果是:" + sum;
18 }
19 }
1 import java.util.concurrent.*;
2
3 //定义一个线程池对象,并测试其特性
4 public class ThreadPoolDemo2 {
5 public static void main(String[] args) throws Exception{
6 //1、创建线程池对象
7 /*
8 public ThreadPoolExecutor(int corePoolSize,
9 int maximumPoolSize,
10 long keepAliveTime,
11 TimeUnit unit,
12 BlockingQueue<Runnable> workQueue,
13 ThreadFactory threadFactory,
14 RejectedExecutionHandler handler)
15 */
16 ExecutorService pool = new ThreadPoolExecutor(3,5,6, TimeUnit.SECONDS,
17 new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
18 //2、给任务线程池处理
19 Future<String> f1 = pool.submit(new MyCallable(100));
20 Future<String> f2 = pool.submit(new MyCallable(200));
21 Future<String> f3 = pool.submit(new MyCallable(300));
22 Future<String> f4 = pool.submit(new MyCallable(400));
23 Future<String> f5 = pool.submit(new MyCallable(500));
24
25 System.out.println( f1.get());
26 System.out.println( f2.get());
27 System.out.println( f3.get());
28 System.out.println( f4.get());
29 System.out.println( f5.get());
30 }
31 }
- 使用Executors的工具方法直接得到一个线程对象
- 补充:定时器3
1 import java.util.Date;
2 import java.util.Timer;
3 import java.util.TimerTask;
4
5 //Timer定时器的使用
6 public class TimerDemo1 {
7 public static void main(String[] args) {
8 //1、创建Timer定时器对象
9 Timer timer = new Timer(); //定时器本身就是单线程
10 //2、调用方法,处理定时任务
11 timer.schedule(new TimerTask() {
12 @Override
13 public void run() {
14 System.out.println(Thread.currentThread().getName() + new Date());
15 System.out.flush();
16 }
17 },3000,2000); //delay :延迟【3秒】, period:周期 【毫秒】
18 }
19 }
1 //ScheduledExecutorService线程池指定定时器
2 public class TimerDemo2 {
3 public static void main(String[] args) {
4 //1、创建ScheduledExecutorService对象
5 ScheduledExecutorService pool = Executors.newScheduledThreadPool(3);
6
7 //2、开启并发任务
8 pool.scheduleAtFixedRate(new TimerTask() {
9 @Override
10 public void run() {
11 System.out.println(Thread.currentThread().getName() + "执行输出AAA -->" + new Date());
12
13 try {
14 System.out.println(10 / 0);
15 Thread.sleep(5000);
16 } catch (Exception e) {
17 e.printStackTrace();
18 }
19
20 }
21 },0,2, TimeUnit.SECONDS); //initalDelay : 初始化延迟时间、period : 周期时间、TimeUnit:时间单位
22
23 pool.scheduleAtFixedRate(new TimerTask() {
24 @Override
25 public void run() {
26 System.out.println(Thread.currentThread().getName() + "执行输出BBB -->" + new Date());
27 }
28 },0,2, TimeUnit.SECONDS); //initalDelay : 初始化延迟时间、period : 周期时间、TimeUnit:时间单位
29
30 }
31 }
可以看到,使用ScheduledExecutorService,一个线程出现问题并不会影响其它线程的正常运行
补充:线程的声明周期:
分类:
Java语言学习笔记
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY