线程通信的前提:线程通信通常是在多个线程操作同一个共享资源的时候需要进行通信,且要保证线程安全。
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任务:
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 }
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,一个线程出现问题并不会影响其它线程的正常运行
补充:线程的声明周期: