主要参考《实战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.
缺点:加锁才能保证线程安全,在并发环境下,可能对性能造成影响。
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类。此外,所有的元数据类、包装类都是使用不变模式实现的。
生产者-消费者是一个经典的多线程设计模式,在生产者-消费者模式中,通常由两类线程,即若干个生产者线程和若干个消费者线程。生产者线程负责提交用户请求,消费者则负责具体处理生产者提交的任务。生产者和消费者之间则通过共享内存缓冲区进行通信。
生产者-消费者模式避免了生产者和消费者直接通信,从而将生产者和消费者进行解耦。生产者不需要直到消费者的存在,消费者也不需要直到生产者的存在。同时,由于内存缓存曲的存在,允许生产者和消费者在执行速度上存在的时间差,缓解生产者和消费者之间的性能差。
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 future = new FutureTask(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 {
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