Java多线程(单例模式、堵塞队列、定时器)

Java多线程

  • 一、单例模式
    • 饿汉模式
    • 懒汉模式
    • 针对单例模式的线程安全要点:
  • 二、堵塞队列
    • 实现BlockingQueue
  • 三、定时器

一、单例模式

单例模式是一种设计模式,针对一些特定的场景,研究出对应的解决方案,。有些对象在代码中只应该有一个实例,单例模式就是强制某个类只能有一个实例。

单例模式的实现,主要依托于static关键字(被static 修饰的成员,静态成员,把当前的成员变成类属性而不是实例属性~)每个类对象只有一份

单例模式实现有两种,饿汉模式和懒汉模式

饿汉模式

饿汉模式实现:实例创建出现在“类加载”阶段(第一次使用到这个类的时候,就会把这个类.class加载到内存里),线程安全

public class TestSinger {
   
    //实现单例模式
    static class Singleton{
   
        //创建一个成员,保存唯一的一个Singleton实例
        private static Singleton instance=new Singleton();
        //提供方法获取实例
        public static Singleton getInstance(){
   
            return instance;
        }
        private Singleton(){
   

        }
    }
    public static void main(String[] args) {
   
        //获取到一个实例 ,只能通过 getInstance 无法通过new 的方式来创建新的Singleton
        Singleton s=Singleton.getInstance();
    }
}

懒汉模式

第一次调用getInstance 方法创建实例 (线程不安全)

public class TestSingleton {
   
    //懒汉模式
    //创建实例的时机是第一次调用时创建,比饿汉模式更迟
    static class Singleton{
   
        private static Singleton instance=null;

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

        private Singleton(){
   

        }
    }

    public static void main(String[] args) {
   
        Singleton s=new Singleton();
    }
}

一般来说懒汉模式更好(但不绝对),懒汉模式更高效,但是饿汉模式是线程安全的,懒汉模式是存在线程不安全的状况,因为懒汉模式有创建线程实例操作,此操作不是原子性,

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

懒汉模式这里操作先进行读操作(LOAD),之后进行比较CMP 之后NEW SAVE(写入内存),如果这里有两个线程执行,会发生抢占式,因为这里操作不是原子性的,所有会发生创建多个实例的情况,出现了BUG,
Java多线程(单例模式、堵塞队列、定时器)_第1张图片

这里我们通过加锁操作来使得操作变为原子性,使得懒汉模式变为线程安全的,可以把锁加到方法上,这时候是针对CMP,NEW 和 SAVE 操作都进行了加锁,三个操作都是串行的,但是这种效率太低了,我们应该把锁作用范围更小一点,针对CMP(判断)和NEW 操作进行加锁,SAVE 只是读操作,并没有修改,不需要加锁,提高效率。

public static Singleton getInstance(){
   
       synchronized (Singleton.class){
   
           if(instance==null){
   
                instance=new Singleton();
             }
        }
     return instance;
	}

但是这样的代码,符出的代价太大了,因为每次调用都会进行加锁,我们只是需要instance未初始化之前,才涉及到线程安全问题,后续已经初始化了,就每次要每次都执行加锁,而是只是进行判断就好了,所以又修改了代码,改为双if判断

public static Singleton getInstance(){
   
           if(instance==null){
   
               synchronized (Singleton.class){
   
                   if(instance==null){
   
                       instance=new Singleton();
                   }
               }
           }
            return instance;
        }

但是这样写还是会有瑕疵,因为在多线程的情况下,可能多个线程进行读操作,由于编译器优化,可能在寄存器读取,而这时候执行操作还没有执行完,还是null的状态,所以我们也要在获取实例时候加上锁

懒汉模式
保证线程安全:
1.加锁,把if判断和new操作加锁
2.双重if循环
3.volatile 关键字

    //懒汉模式
    static class Singleton

你可能感兴趣的:(web)