关于java:并发并发设计模式

6次阅读

共计 2233 个字符,预计需要花费 6 分钟才能阅读完成。

写并发程序时, 很多问题前人曾经终结了有模板套的编程模式, 遇到类似的问题时套用模式无需从头从新思考实现. 防止 bug 的产生, 以下列举了并发编程罕用的一些模式与应用场景

  • 不变模式

多线程环境下, 能 final 的尽量 final 润饰. 这点能够配合 ” 写时复制 ” 一起了解, 如 copyOnWriteArray 写时并没有改变原先的数组 (也就是不可变),
润饰成 final 并不是就意味着线程平安, 因为只是援用不可变, 对象属性还是多线程批改的. 同时还要留神 “ 不平安公布 ” 的问题(如办法返回爱护对象援用)

  • 线程关闭

即共享变量只有持有的线程这一个线程能够拜访, 不让共享, 也就线程平安了. 这就是线程关闭的含意. 对应于 java 中, 指的就是 ThreadLocal

  • Guarded Suspension 模式

翻译过去能够是 ” 有保障的停止 ”, 总感觉怪怪的, 其实说的就是 多线程的 期待告诉模型. 如下异步转同步的场景就用到这种模式

public class DefaultFuture<T> {
    /**
     * 后果对象
     */
    private T obj;
    private final Lock lock = new ReentrantLock();
    private final Condition done = lock.newCondition();
    private final int timeout = 2;

    final static Map<Object, DefaultFuture> fs = new ConcurrentHashMap<>();

    /**
     * 静态方法创立 GuardedObject(DefaultFuture)
     * @param key
     * @param <K>
     * @return
     */
    public static <K> DefaultFuture create(K key) {DefaultFuture f = new DefaultFuture();
        fs.put(key, f);
        return f;
    }

    public static <K, T> void fireEvent(K key, T obj) {DefaultFuture go = fs.remove(key);
        if (go != null) {go.onChanged(obj);
        }
    }

    /**
     * 返回后果对象
     */
    public T get(Predicate<T> p) {lock.lock();
        try {
            //MESA 管程举荐写法
            while (!p.test(obj)) {done.await(timeout, TimeUnit.SECONDS);
            }
        } catch (InterruptedException e) {throw new RuntimeException(e);
        } finally {lock.unlock();
        }

        return obj;
    }


    public void onChanged(T obj) {lock.lock();
        try {
            this.obj = obj;
            done.signalAll();} finally {lock.unlock();
        }
    }

}
  • COW, 即 copy on write 模式

实用于 保护数据量少, 读多写少的场景. 如 rpc 调用外面的路由信息保护, 元数据保护, 缓存等场景.
留神: 因为写时复制, 先 copy,copy 完后, 而后调整援用指向. 故读时会有短暂的不统一. 用到的时候须要思考到场景是否可能容忍这种不统一景象.

  • balking 模式

与其说是一种模式, 还不如说是对 ” 同步 ” 概念的进一步思考. 如果多线程场景含有 ” 条件依赖 ” 的语义,(如单例初始化, 如果没有初始化才初始化)
这就没必要将整个实例化办法加锁. 只须要对实例化办法块加锁. 如下所示相比于对整个 getInstance 办法加锁, 曾经实例化的状况性能会更高.


class Singleton{
  private static volatile  Singleton singleton;
  // 构造方法私有化  
  private Singleton() {}
  // 获取实例(单例)public static Singleton  getInstance() {
    // 第一次查看
    if(singleton==null){synchronize(Singleton.class){
        // 获取锁后二次查看
        if(singleton==null){singleton=new Singleton();
        }
      }
    }
    return singleton;
  }
}
  • Work per Thread

即每个工作一个线程,java 中的线程属于特地耗费占资源的对象, 用原生的不可行. 轻量级线程 (协程) 可采纳此模式,java 开源我的项目 Loom 我的项目的 Fiber
据说能够实现, 有空能够钻研下

  • Work-Thread 模式

也就是线程池模式. 须要留神的是线程池里的工作每个工作须要各自独立, 防止有依赖关系, 不然的话有死锁危险.
呈现这种问题的解决办法是, 将相互有依赖的线程放在不同的池中执行.

  • 两阶段终止协定(thread.interrupt)

java 中的中断并不是粗鲁的一刀切中断, 而是通过中断标识符, 将中断后的解决逻辑交给须要被中断的线程来解决

  1. 抛出 interruptException 后, 以后线程的中断标识会被革除. 故捕捉到异样后, 须要从新设置异样标识(Thread.currentThread().interrupt())
  2. 如果解决中断的线程中援用了第三方包, 可能第三方包没有正确处理中断异样(如未从新设置中断标识), 这种状况下最好本人新建一个

中断状态, 线程的中断依赖于本人建的这个状态, 而非线程自带的.

  • 生产者 - 消费者模式.

也是最多使用的一种多线程协同模式, 用的最多, 不做开展

正文完
 0