尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

JavaEE初阶 多线程:单例模式 | 阻塞队列

JavaEE初阶 多线程:单例模式 | 阻塞队列 目录Singleton 单例模式饿汉模式运行即创建懒汉模式需要时再创建线程安全问题阻塞队列阻塞队列实现阻塞队列的使用阻塞队列作用Singleton 单例模式单例模式能保证某个类在程序中只存在唯⼀⼀份实例,⽽不会创建出多个实例。单例模式最常⻅的实现⽅的是饿汉和懒汉两种饿汉模式运行即创建class Singleton{ private static Singleton instancenew Singleton(); private static Singleton getinstance(){ return instance; } //构造方法私有化仅限在Singleton类中实例化确保单例化 private Singleton(){ } }懒汉模式需要时再创建class Singleton{ private static Object lockernew Object(); //volatile修饰instance private static volatile Singleton instancenull; public static Singleton getinstance(){ if (instancenull){ synchronized (locker){ if (instancenull){ instancenew Singleton(); } } } //实例化时原子操作 return instance; } //构造方法私有化仅限在Singleton类中实例化确保单例化 private Singleton(){ } }线程安全问题饿汉模式不存在线程安全问题懒汉模式当多个线程调用getInstance⽅法,就可能导致创建 出多个实例后面的实例会覆盖前面实例资源浪费。⼀旦实例已经创建好了,后⾯再多线程环境调⽤getInstance就不再有线程安全问题了(不再修改 instance 了使用锁保证原子性//判断是否需要加锁已经创建实例后减少资源浪费 if (instancenull){ synchronized (locker){ //判断是否需要实例化 if (instancenull){ instancenew Singleton(); } } }通过volatile关键字修饰但线程在加锁操作时仍会被调度导致t1线程中instance使用了未初始化的实例因此需要加入volatile避免重排序对数据库使用单例模式class DBUtil { private static volatile DataSource dataSource null; public static DataSource getInstance() { if (dataSource null) { synchronized (DBUtil.class) { if (dataSource null) { MysqlDataSource ds new MysqlDataSource(); ds.setUrl(jdbc:mysql://127.0.0.1:3306/java117?characterEncodingutf8useSSLfalse); ds.setUser(root); ds.setPassword(2222); dataSource ds; } } } return dataSource; } private DBUtil{} }阻塞队列阻塞队列是⼀种特殊的队列.也遵守先进先出的原则具有线程安全的阻塞队列1.当队列满的时候,继续⼊队列就会阻塞,直到有其他线程从队列中取⾛元素.2.当队列空的时候,继续出队列也会阻塞,直到有其他线程往队列中插⼊元素.阻塞队列实现class Queue{ private int[] Arrayqueue; int tail0; int head0; int size0; public Queue(int capacity){ Arrayqueuenew int[capacity]; } Object lockernew Object(); public void put(int n) throws InterruptedException { //判满返回 //线程安全 synchronized (locker){ /*if(sizeArrayqueue.length){ //阻塞等待 locker.wait(); }*/ //wait被唤醒时会重新检擦size是否符合要求 while (sizeArrayqueue.length){ locker.wait(); } Arrayqueue[head]n; head(head1)%Arrayqueue.length; size; locker.notifyAll(); } } public int take() throws InterruptedException { synchronized (locker){ /*if (size0){ locker.wait(); }*/ while (size0){ locker.wait(); } int n Arrayqueue[tail]; tail(tail1)% Arrayqueue.length; size--; locker.notifyAll(); return n; } } }阻塞的队列的应用场景生产消费者模型生产者线程用来生产产出放入阻塞队列消费者线程从阻塞队列取出产品消费阻塞队列的使用在Java标准库中内置了阻塞队列.如果我们需要在⼀些程序中使⽤阻塞队列,直接使⽤标准库中的即 可.1.BlockingQueue是⼀个接⼝.真正实现类包括LinkedBlockingQueue/ArrayBlockingQueue/PriorityBlockingQueue.2.put⽅法⽤于阻塞式的⼊队列,take⽤于阻塞式的出队列.3.BlockingQueue也有offer,poll,peek等⽅法,但是这些⽅法不带有阻塞特性public static void main(String[] args) { // BlockingDequeInteger queuenew LinkedBlockingDeque(); // BlockingQueueInteger queuenew ArrayBlockingQueue(100); //BlockingDequeInteger queue new PriorityBlockingQueueInteger(); Queue queuenew Queue(100); Thread t0new Thread(()-{ int n0; while (true){ try { queue.put(n); System.out.println(生产了: n); n; } catch (InterruptedException e) { throw new RuntimeException(e); } try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } }); Thread t1new Thread(()-{ //int n0; while (true){ //int n 0; try { int n queue.take(); System.out.println(消费了: n); } catch (InterruptedException e) { throw new RuntimeException(e); } } }); t0.start(); t1.start(); }阻塞队列作用1.减少资源竞争,生产消费者各司其职2.解耦合浏览器下单通过网关传递服务器a再通过服务器b处理返回如果b出现问题直接影响a处理通过阻塞队列 a与队列耦合b与队列耦合3.削峰填谷当某个时间段访问量激增阻塞队列会先接受访问量等待服务器处理减缓服务器压力
返回列表