单例模式,阻塞队列的认识

文章详细介绍了Java中的单例模式,包括饿汉模式和懒汉模式,并讨论了线程安全问题及volatile关键字的作用。接着,文章阐述了阻塞队列的概念,强调其在生产者-消费者模型中的应用,以及使用BlockingQueue实现阻塞功能,并给出自定义阻塞队列的示例代码。
摘要由CSDN通过智能技术生成

多线程案例

一.单例模式(是常见的设计模式)

**
设计模式:代码里面程序猿水平参差不齐,写的代码也各有好坏,所以有些大佬根据一些场景需求,整理出对应的应对方法,这样可以提高程序猿的整体代码水平,整理出的这些对应方法就叫做设计模式.

  • 定义
    单例模式:单个的实例或者线程.本质上就是借助编程语言自身的语法特性,强行限制某个类,不能创建多个实例.

  • 用static关键字则可以限制只能创建一个类
    1.当属性变成类属性,已经是单个实例.更具体的的说是类对象属性,类对象是通过jvm加载(.class)文件,而此时类对象在jvm中也是实例.(jvm针对某个.class文件只会加载一次,也就只有一个类对象,类对象上面的成员static修饰的也只有一份)

在这里插入图片描述
2.static应用
在C语言中:
1.static修饰局部变量,改变变量生命周期
2.static修饰全局变量,改变变量作用域
3.static修饰方法,改变函数作用域
在Java语言中:
1.当static修饰类里面的成员变量

二.实现单例模式代码

**

  • 饿汉模式
    在这里插入图片描述
  • 懒汉模式(创建实例更迟,带来效率更高)
    在这里插入图片描述
    懒汉操作是不安全的

在这里插入图片描述
如果t2线程进行load读操作时,t1还没有修改完,t2读的还是旧值,t2仍然能进入new操作,此时就会导致出现多个实例

如何保证懒汉模式线程安全—>加锁(希望t2读的是t1修改后的值)
在这里插入图片描述

实例创建之前线程是不安全需要加锁,实例创建之后,线程就安全不需要加锁
在这里插入图片描述
假设这两个线程同时调用getinstance,第一个线程进入锁以后进入第2个if开始new对象.
这时底层会有3个操作:
1.申请内存,得到内存首地址
2.调用勾走方法,初始化实例
3.把内存首地址赋给instance引用
而这样可能会导致编译器出现"指令重排序"优化

在这里插入图片描述
假设触发指令重排序,t1先执行申请内存和把内存地址赋给instance引用,此时得到不完全对象,只是内存,并没有内存上的数据,当t2线程调用getinstance就会认为这个实例为非空,就直接返回,并且在后面也会对instance进行解引用操作.

怎样能禁止指令重排序-----使用(volatile)
在这里插入图片描述

三.阻塞队列

  • 阻塞队列是一种特殊队列,遵循先进先出原则

  • 线程是安全的

  • 带有阻塞功能

  • 如果队列满,继续入队列,入队就会阻塞,直到有其他线程从队列里面取出元素

  • 如果队列空,继续出队列,出队就会阻塞,直到有其他线程给队列里面放入元素

  • 应用场景:实现生产者,消费者模型(多线程协同工作一种方式)

  • 优势:
    1:使用阻塞队列有利于代码解耦合,使得生产者和消费者之间没有太多的关联性,生产者生产完数据直接扔给阻塞队列,消费者需要数据直接从阻塞队列里面拿,就不需要经过生产者了.
    2.阻塞队列相当于一个缓冲区,平衡了消费者和生产者.(服务器每处理一个请求,都是需要消耗硬件资源,同一时刻请求越多,消耗资源就会越多.一台主机上资源是有限的,某个资源耗尽,机器也就直接停止运转了.)

  • 阻塞队列具体应用

-标准库阻塞队列----BlockingQueue

在这里插入代码片
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;

public class Demo21 {
    public static void main(String[] args) throws InterruptedException {
        BlockingDeque<Integer>blockingDeque=new LinkedBlockingDeque<>(100);
        //带有阻塞功能入队
        blockingDeque.put(1);
        blockingDeque.put(2);
        blockingDeque.put(3);
        //带有阻塞功能的出队列
        Integer ret=blockingDeque.take();
        System.out.println(ret);
        ret=blockingDeque.take();
        System.out.println(ret);
        
    }
}

阻塞队列没有提供带有阻塞功能的取队首元素

  • 自己实现一个阻塞队列(用数组)

思想: 1.先实现一个普通队列,基于数组循环队列 2.加上线程安全 3.加上阻塞功能

在这里插入代码片
class  MyBlockingQueue{
    private int[] nums=new int[100];
    private volatile int head=0;//头指针
    private volatile int tail=0;//尾指针
    private volatile int size=0;//计数器
    //入队
    public void put(int num) throws InterruptedException {
        synchronized (this) {
            while (size >= nums.length) {
                //满了
                this.wait();//满了就会出现锁竞争
            }
            nums[tail] = num;
            tail++;
            if (head >= nums.length) {
                tail = 0;
            }
            size++;
            this.notify();
        }
    }
    //出队
    public  Integer take() throws InterruptedException {
            synchronized (this){
                while (size==0){
                    this.wait();//出队列空了也会出现锁竞争
                }
                int ret=nums[head];
                head++;
                if (head>=nums.length){
                    head=0;
                }
                size--;
                this.notify();
                return ret;
            }
    }
}
public class Demo22 {
    public static void main(String[] args) {
        MyBlockingQueue myBlockingQueue=new MyBlockingQueue();
        Thread t1=new Thread(()->{
            int n=1;
            while (true){
                try {
                    myBlockingQueue.put(n);
                    System.out.println("生产元素"+n);
                    n++;
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        Thread t2=new Thread(()->{
            while (true){
                try {
                    int n=myBlockingQueue.take();
                    System.out.println("消费元素"+n);
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }

            }
        });
        t1.start();
        t2.start();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值