美文网首页
多线程与并发(十):多线程同步模式

多线程与并发(十):多线程同步模式

作者: lilykeke | 来源:发表于2021-09-10 09:22 被阅读0次

* 同步模式之两阶段终止(Two Phase Termination)

在一个线程 t1 如何优雅结束线程 t2 ? 优雅的意思是:给线程t2 一个料理后事的机会

  1. 错误思路
  • 使用线程对象的stop 方法停止线程
    • stop 方法会真正杀死线程,如果这时线程锁住了共享资源,那么当他被杀死后,就再也没有机会释放锁,其他线程将永远无法获取锁
  • 使用System.exit(int)方法停止线程
    • 目的仅是停止一个线程,但这种做法会让整个程序都停止

例如:要做一个系统的健康状况监控,没个两秒记录一次

两阶段终止模式.jpg
public class InterruptModeTest {

    public static void main(String[] args) {
        TwoPhaseTermination twoPhaseTermination = new TwoPhaseTermination();
        twoPhaseTermination.start();

        try {
            Thread.sleep(3500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        twoPhaseTermination.stop();
    }
}
class TwoPhaseTermination{
    private Thread monitor;

    //启动监控线程
    public void start(){
        monitor = new Thread(()->{
            while (true){
                if (Thread.currentThread().isInterrupted()){
                    System.out.println("料理后事");
                    break;
                }

                try {
                    Thread.sleep(1000); //情况一:睡眠过程中被打断
                    System.out.println("执行监控..."); //情况二
                } catch (InterruptedException e) {
                    e.printStackTrace();

                    Thread.currentThread().interrupt(); //重新设置打断标记
                }

            }
        });

        monitor.start();
    }

    //终止线程
    public void stop(){
        monitor.interrupt();
    }
}

执行结果:
执行监控...
执行监控...
执行监控...
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at com.lily.base.TwoPhaseTermination.lambdastart0(InterruptModeTest.java:32)
at java.lang.Thread.run(Thread.java:748)
料理后事


细节一:sleep 时打断
细节二:执行监控记录时打断

同步模式之保护性暂停

即Guarded Suspension, 用在一个线程等待另一个线程的执行结果。

要点

  • 有一个结果需要从一个线程传递到另一个线程,让他们关联同一个GuardedObject

  • 如果有结果不断从一个线程到另一个线程那么可以使用消息队列(见生产者/消费者)

  • JDK中,join 的实现,Future 的实现,采用的就是此模式

  • 因为要等待另一方的结果,因此归类到同步模式


    保护性暂停.jpg
  • 代码实现

保护性暂停-扩展-增加超时

join方法

看一下join 的源码

保护性暂停-扩展-解耦等待和生产-分析

图中Futures就好比居民楼一层的信箱(每个信箱有房间编号),左侧的t0,t2,t4就好比等待邮件的居民,右侧t1,t3,t5就好比邮递员。

如果需要在多个类之间使用GuardedObject 对象,作为参数传递不是很方便,因此设计一个用来解耦的中间类,这样不仅能够解耦【结果等待者】和【结果生产者】,还能够同时支持多个任务的管理。

异步模式之工作线程

  1. 定义
    让有限的工作线程来轮流异步处理无限多的任务。也可以将其归类为分工模式,它的典型实现就是线程池,也体现了经典设计模式中的享元模式。

例如,海底捞的服务员(线程),轮流处理每位客人的点餐(任务),如果每位客人都配备一名专属的服务员,那么成本就太高了(对比另一种多线程设计模式:Thread-Per-Message)

注意,不同任务类型应该使用不同的线程池,这样能够避免饥饿,并能提升效率

例如,如果一个餐馆的工人既要招呼客人,又要到后厨做菜显然效率不高,分成服务员(线程池A),厨师(线程池B)更为合理,当然你能想到更细致的分工。

2.饥饿

固定大小线程池会有饥饿现象

  • 两个工人是同一个线程池的两个线程
  • 他们要做的事是:为客人点餐和到后厨做菜,这时两个阶段的工作。
    • 客人点餐:必须先点完餐,等菜做好,上菜,在此期间处理点餐的工人必须等待
    • 后厨做菜:没啥说的,做就是了
  • 比如工人A处理了点餐任务,接下来它要等着工人B把菜做好,然后上菜,他两也配合的蛮好的
  • 但现在同时来了两个客人,这个时候工人A 和 工人B 都去处理点餐了,这时没人做菜了,死锁
public class TestDeadLock {

    static final List<String> MENU = Arrays.asList("地三鲜","宫保鸡丁","辣子鸡丁","烤翅");
    static Random RANDOM = new Random();
    static String cooking(){
        return MENU.get(RANDOM.nextInt(MENU.size()));
    }

    public static void main(String[] args) throws InterruptedException{
        ExecutorService pool = Executors.newFixedThreadPool(2);

        pool.execute(()->{
            System.out.println("处理点餐...");

            Future<String> f = pool.submit(()->{
                System.out.println("做菜");
                return cooking();
            });

            try {
                System.out.println("上菜 " + f.get());
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }

        });

        pool.execute(()->{
            System.out.println("处理点餐...");

            Future<String> f = pool.submit(()->{
                System.out.println("做菜");
                return cooking();
            });

            try {
                System.out.println("上菜 " + f.get());
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }

        });
    }
}

执行结果:
处理点餐...
处理点餐...


饥饿解决
不同的任务类型使用不同的线程池

public class TestDeadLock {

   static final List<String> MENU = Arrays.asList("地三鲜","宫保鸡丁","辣子鸡丁","烤翅");
   static Random RANDOM = new Random();
   static String cooking(){
       return MENU.get(RANDOM.nextInt(MENU.size()));
   }

   public static void main(String[] args) throws InterruptedException{
       ExecutorService orderPool = Executors.newFixedThreadPool(2);
       ExecutorService cookPool = Executors.newFixedThreadPool(2);

       orderPool.execute(()->{
           System.out.println(Thread.currentThread().getName() + " 处理点餐...");

           Future<String> f = cookPool.submit(()->{
               System.out.println(Thread.currentThread().getName() + " 做菜");
               return cooking();
           });

           try {
               System.out.println(Thread.currentThread().getName() + " 上菜 " + f.get());
           } catch (InterruptedException | ExecutionException e) {
               e.printStackTrace();
           }

       });

       orderPool.execute(()->{
           System.out.println(Thread.currentThread().getName() + " 处理点餐...");

           Future<String> f = cookPool.submit(()->{
               System.out.println(Thread.currentThread().getName() + " 做菜");
               return cooking();
           });

           try {
               System.out.println(Thread.currentThread().getName() +" 上菜 " + f.get());
           } catch (InterruptedException | ExecutionException e) {
               e.printStackTrace();
           }

       });
   }
}

执行结果:
pool-1-thread-1 处理点餐...
pool-1-thread-2 处理点餐...
pool-2-thread-1 做菜
pool-1-thread-2 上菜 烤翅
pool-2-thread-2 做菜
pool-1-thread-1 上菜 辣子鸡丁


相关文章

  • 多线程与并发(十):多线程同步模式

    * 同步模式之两阶段终止(Two Phase Termination) 在一个线程 t1 如何优雅结束线程 t2 ...

  • iOS - Multi-Thread

    概念篇 进程 线程 多线程 单核多线程 & 多核多线程 并行 & 并发 同步 & 异步 队列 队列 & 任务 的执...

  • RAC 与 多线程

    07 - RAC与多线程 RAC怎么实现多线程并发处理订阅? RAC多线程模式怎么解决资源抢夺? RAC怎么实现取...

  • 多线程

    GCD NSOperation NSThread 多线程与锁 一、GCD 同步、异步 和 串行、并发 dispat...

  • Java多线程并发之同步容器和并发容器-第一篇

    Java多线程并发之同步容器和并发容器-第一篇 概述 本文主要讲解在Java多线程并发开发中,集合中有哪些支持并发...

  • 多线程相关面试问题

    多线程:GCD、NSOperation、NSThread。 一、GCD 1、同步/异步 和 串行/并发(1)、同步...

  • 理解java集合

    容器的同步控制与只读设置 一、同步控制:多线程并发访问集合的线程安全常用的容器ArrayList、HashSet、...

  • 10信号量与管程

    18.1信号量 回顾 ■并发问题 多线程并发导致资源竞争 ■同步概念 协调多线程对共享数据的访问 任何时刻只能有一...

  • 多线程并发 (五) ReentrantLock 使用和源码

    章节: 多线程并发 (一) 了解 Java 虚拟机 - JVM 多线程并发 (二) 了解 Thread 多线程并发...

  • iOS面试之多线程模块

    多线程 多线程内容如下: GCD NSOperation NSThread 多线程与锁 1.GCD 同步/异步和串...

网友评论

      本文标题:多线程与并发(十):多线程同步模式

      本文链接:https://www.haomeiwen.com/subject/agormktx.html