与并发有关的设计模式

主要参考《实战java高并发程序设计》

一、 单例设计模式

单例设计模式是一种对象创建模式,用于产生一个对象得具体实例,它可以确保系统中一个类只产生一个实例。

这样做得好处:1.对于频繁使用的对象,可以省略new操作花费的时间。2. 由于new操作次数的减少,因而对系统内存的使用频率也会降低,这将减轻GC压力,缩短GC停顿时间。

单例实际模式与并发关系不大,但在多线程环境中会用到单例设计模式,所以需要实现一种高效的单例实现。

1. ”饿汉式“,第一次调用这个类时就会创建这个类的对象,显得很着急,所以称为”饿汉式“。是线程安全的,也很简单。

public class Singleton {
    public static int status = 1;
    private Singleton(){
        System.out.println("Singleton is created");
    }
    private static Singleton instance = new Singleton();
    public static Singleton getInstance(){
        return instance;
    }
}

优点:简单,并发模式下性能高。

缺点:类中有其他静态成员被调用,即使getInstance()方法没被调用,由于类被加载,instance被创建,也会执行Singleton()方法。

2. ”懒汉式“,延迟加载,只有在调用getInstance()时,创建instance.

public class LazySingleton {
    public static int status =1;
    private LazySingleton() {
        System.out.println("LazySingleton is created");
    }

    private static LazySingleton instance = null;

    public static synchronized LazySingleton getInstance() {
        if (instance == null)
            instance = new LazySingleton();
        return instance;
    }
}

优点:只有在调用getInstance()时,才会创建instance.

缺点:加锁才能保证线程安全,在并发环境下,可能对性能造成影响。

3.

4. 结合1,2的优点,克服1,2的缺点,使用内部类的方式,只有在调用getInstance()时才会创建instance,而且不加锁也可以保证线程安全。

public class StaticSingleton {
    private StaticSingleton(){
        System.out.println("StaticSingleton is created");
    }
    // 内部类没被调用前不会被加载
    private static class SingletonHolder{
        private static StaticSingleton instance = new StaticSingleton();
    }
    public static StaticSingleton getInstance(){
        return SingletonHolder.instance;
    }
}

 二、不变模式

只所以有同步问题,是因为不同线程在操作同一资源时,可能同时修改它,造成线程安全问题。如果一个对象,不可修改,就不会出现同步问题了。

不变模式和只读属性有一定的区别。

不变模式的应用场景:

实现不变模式的4个要点:

在JDK中,不变模式的应用非常广泛。其中,最为典型的就是java.lang.String类。此外,所有的元数据类、包装类都是使用不变模式实现的。 

三、生产者-消费者模式

生产者-消费者是一个经典的多线程设计模式,在生产者-消费者模式中,通常由两类线程,即若干个生产者线程和若干个消费者线程。生产者线程负责提交用户请求,消费者则负责具体处理生产者提交的任务。生产者和消费者之间则通过共享内存缓冲区进行通信。

生产者-消费者模式避免了生产者和消费者直接通信,从而将生产者和消费者进行解耦。生产者不需要直到消费者的存在,消费者也不需要直到生产者的存在。同时,由于内存缓存曲的存在,允许生产者和消费者在执行速度上存在的时间差,缓解生产者和消费者之间的性能差。

四、Future模式

1.Future模式是什么

Future模式是多线程开发中非常常见的一种设计模式,它的核心思想是异步调用。当我们需要调用一个函数方法时,如果这个函数执行得很慢,那么我们就要进行等待。但有时候,我们其他操作可能不依赖这个结果。因此,我们可以让被调者返回,让它在后台慢慢处理这个请求。对于调用者来说,则可以先处理一些其他任务,在真正需要数据得场合再去尝试获得需要得数据。

2.JDK中得Future模式

一个例子:



import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;

public class FutureMain {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<String> future = new FutureTask<String>(new RealData("a"));
        ExecutorService executor = Executors.newFixedThreadPool(1);
        executor.submit(future);

        System.out.println("请求完毕");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if(future.isDone()){
            System.out.println("任务完成");
        }
        System.out.println("数据 = " + future.get());
    }
}


import java.util.concurrent.Callable;

public class RealData implements Callable<String> {
    private String para;
    public RealData(String para) {
        this.para = para;
    }

    @Override
    public String call() throws Exception {
        StringBuffer sb = new StringBuffer();
        for(int i=0;i<10;i++){
            sb.append(para);
            Thread.sleep(100);
        }
        return sb.toString();
    }
}

3.FutureTask实现

runnable和callable的区别 https://blog.csdn.net/HEYUTAO007/article/details/19072675

注意:

1.FutureTask对象task,task.get()方法会在没有得到返回值时,阻塞调用线程。

2.task需要用Thread包装才能开启新线程,直接调用run()方法还是在调用线程中执行

3.调用cancel方法后,再调用get()方法,会报异常

源码分析:

https://www.jianshu.com/p/fdef785bb287

https://www.jianshu.com/p/69a6ae850736

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值