多线程——单例模型、阻塞队列

目录

一、单例模型

        1、饿汉模式

        2、懒汉模式

二、阻塞队列

        1、阻塞队列原理

        2、阻塞队列常见用法

        3、生产者消费者模型


一、单例模型

        单例模式,是设计模式(针对问题使用不同方式解决问题)中一种非常经典的模式,而单例模式就如其名字一样,强制要求一个类不能创建多个对象

        而单例模型大概分俩种,一种是饿汉模式,一种是懒汉模式

        1、饿汉模式

        饿汉模式,听名字就知道是非常饥饿,而在java中的意思就是在类加载的同时,创建实例

        

class Singleton{
    private static Singleton instance=new Singleton(100);

    public static Singleton getInstance() {
        return instance;
    }

    private Singleton(){

    }

    private Singleton(int n){

    }
}

         而在过程中,只能返回一个实例,不能返回多个,不然会报错,这一点在很多场景上都需要. 比如 JDBC 中的 DataSource 实例就只需要一个。

        2、懒汉模式

        而懒汉模式和饿汉模式恰恰相反,懒汉模式是使用的时候再创建实例,不使用不创建实例。同时,懒汉模式也有分为单线程和多线程类。单线程如下:

        

class SingletonLazy{
    private static SingletonLazy instance=null;
   
    public static SingletonLazy getInstance2(){
        if(instance==null){
            instance=new SingletonLazy();
        }
        return instance;
    }

    private  SingletonLazy(){

    }
}

        在上述中懒汉模式是需要用的时候再创建实例,不需要就不用,对于单线程来说这个是可以的,但对于多线程中的话,因为多线程不是原子性的,所以在同时调用getInstance2方法的话,就很有可能会导致创建多个实例,所以,为了杜绝这个问题,我们需要加上synchronized来改善这里的线程安全问题。

        

class SingletonLazy{
    private static volatile SingletonLazy instance=null;
    private static  Object locker=new Object();

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

    private  SingletonLazy(){

    }
}

        用双重if来降低锁竞争,然后再用voliatile解决可见性问题,这样的话就能解决线程安全问题。

二、阻塞队列

        1、阻塞队列原理

        阻塞队列是什么?阻塞队列其实就是一种特殊的队列,遵守“先进先出”的原则。

        我们以图为例子:

        

         这是一个很普通的客户端A向服务器B发起请求,如果没有阻塞队列的话,那么就直接全部数据一起传输,如果有阻塞的话,就会变成下面情况:

        在客户端A向客户端B发出请求的时候,中间有阻塞队列,如果里面队满(阻塞队列存储满),而不能够入队列,直到队列不满。如果队列为空,则不能够出队列,直到队列不为空。

        

        2、阻塞队列常见用法

        阻塞队列最常用的就是put和take方法,put方法就是将元素添加到阻塞队列,而take则是拿出来,有一点十分注意的是,阻塞队列中有offer的方法,但使用这个是不会被阻塞的,就会变成一个普通的队列。

        

 public static void main(String[] args) throws InterruptedException {
        BlockingQueue<String> queue=new LinkedBlockingQueue<>(10);
        for (int i = 0; i < 10; i++) {
            queue.put("aaa");
        }
        System.out.println("队列已满");

        for (int i = 0; i < 10; i++) {
            System.out.println(queue.take());
        }
        System.out.println("队列为空");
        queue.take();
    }

        3、生产者消费者模型

        而我们对于阻塞队列中有关的的有生产者消费者模型,这个案例十分典型,解释一下什么是生产者消费者模型,在一个阻塞队列中,生产速度大于消费速度,那么当生产量和消费量的差值已经是阻塞队列的大小之后,那么就会进行阻塞,直到保证生产量和消费量的差值比阻塞队列的大小还小,这样就能做到生产者和消费者之间的硬性平衡。以下面为案例:

        

  public static void main(String[] args) {
        BlockingQueue<Integer> queue=new LinkedBlockingQueue<>(4);
        Thread producer=new Thread(()->{
            int n=0;
            while (true){
                try {
                    queue.put(n);//offer不会阻塞,put才行
                    System.out.println("生产元素"+n);
                    n++;
                    Thread.sleep(1000);
                }catch(InterruptedException e){
                    throw new RuntimeException(e);
                }
            }
        },"producer");

        Thread consumer=new Thread(()->{
            while(true){
                try{
                    Integer n=queue.take();
                    System.out.println("消费元素"+n);

                    Thread.sleep(3000);
                }catch(InterruptedException e){
                    throw new RuntimeException(e);
                }
            }
        },"consumer");
        producer.start();
        consumer.start();
    }

         在上面图中,生产的速度是一秒一个,而消费的速度是三秒一个,但阻塞队列的大小为4,所以当生产元素减去消费元素>=4的时候,就会进行阻塞,直到差值小于4.

     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值