目录
Singleton 单例模式
饿汉模式,运行即创建
懒汉模式,需要时再创建
线程安全问题
阻塞队列
阻塞队列实现
阻塞队列的使用
阻塞队列作用
Singleton 单例模式
单例模式能保证某个类在程序中只存在唯⼀⼀份实例,⽽不会创建出多个实例。
单例模式最常⻅的实现⽅的是"饿汉"和"懒汉"两种
饿汉模式,运行即创建
class Singleton{
private static Singleton instance=new Singleton();
private static Singleton getinstance(){
return instance;
}
//构造方法私有化,仅限在Singleton类中实例化,确保单例化
private Singleton(){
}
}
懒汉模式,需要时再创建
class Singleton{
private static Object locker=new Object();
//volatile修饰instance
private static volatile Singleton instance=null;
public static Singleton getinstance(){
if (instance==null){
synchronized (locker){
if (instance==null){
instance=new Singleton();
}
}
}
//实例化时原子操作
return instance;
}
//构造方法私有化,仅限在Singleton类中实例化,确保单例化
private Singleton(){
}
}
线程安全问题
饿汉模式不存在线程安全问题,懒汉模式当多个线程调用getInstance⽅法,就可能导致创建 出多个实例,后面的实例会覆盖前面实例,资源浪费。

⼀旦实例已经创建好了,后⾯再多线程环境调⽤getInstance就不再有线程安全问题了(不再修改 instance 了)
使用锁保证原子性
//判断是否需要加锁,已经创建实例后减少资源浪费
if (instance==null){
synchronized (locker){
//判断是否需要实例化
if (instance==null){
instance=new 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?characterEncoding=utf8&useSSL=false");
ds.setUser("root");
ds.setPassword("2222");
dataSource = ds;
}
}
}
return dataSource;
}
private DBUtil{}
}
阻塞队列
阻塞队列是⼀种特殊的队列.也遵守"先进先出"的原则,具有线程安全的阻塞队列
1.当队列满的时候,继续⼊队列就会阻塞,直到有其他线程从队列中取⾛元素.
2.当队列空的时候,继续出队列也会阻塞,直到有其他线程往队列中插⼊元素.
阻塞队列实现
class Queue{
private int[] Arrayqueue;
int tail=0;
int head=0;
int size=0;
public Queue(int capacity){
Arrayqueue=new int[capacity];
}
Object locker=new Object();
public void put(int n) throws InterruptedException {
//判满返回
//线程安全
synchronized (locker){
/*if(size==Arrayqueue.length){
//阻塞等待
locker.wait();
}*/ //wait被唤醒时会重新检擦size是否符合要求
while (size==Arrayqueue.length){
locker.wait();
}
Arrayqueue[head]=n;
head=(head+1)%Arrayqueue.length;
size++;
locker.notifyAll();
}
}
public int take() throws InterruptedException {
synchronized (locker){
/*if (size==0){
locker.wait();
}*/
while (size==0){
locker.wait();
}
int n= Arrayqueue[tail];
tail=(tail+1)% 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) {
// BlockingDeque<Integer> queue=new LinkedBlockingDeque<>();
// BlockingQueue<Integer> queue=new ArrayBlockingQueue<>(100);
//BlockingDeque<Integer> queue= new PriorityBlockingQueue<Integer>();
Queue queue=new Queue(100);
Thread t0=new Thread(()->{
int n=0;
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 t1=new Thread(()->{
//int n=0;
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.削峰填谷

当某个时间段访问量激增,阻塞队列会先接受访问量,等待服务器处理,减缓服务器压力
网硕互联帮助中心



评论前必须登录!
注册