如何做拉勾勾网站,宁波网站制作公司费用价格,软件商店下载到手机,wordpress 漏洞修复前言 逆水行舟#xff0c;不进则退#xff01;#xff01;#xff01; 目录 单例模式 饿汉模式#xff1a; 懒汉模式#xff1a; 什么是阻塞队列 什么是高内聚 低耦合 阻塞队列的实现 单例模式 单例模式#xff08;Singleton Pattern#xff09;是一种常见… 前言 逆水行舟不进则退 目录 单例模式 饿汉模式 懒汉模式 什么是阻塞队列 什么是高内聚 低耦合 阻塞队列的实现 单例模式 单例模式Singleton Pattern是一种常见的设计模式主要应用于创建型模式。它确保一个类只有一个实例并且自行负责实例化并向整个系统提供这个唯一实例。此外这种模式属于创建型模式通过这种方式创建的类在当前进程中只存在一个实例。 在计算机系统中诸如线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例因为它们在整个应用程序中只需要一个实例。然而尽管单例模式是应用最广的设计模式之一也是程序员非常熟悉的一种设计模式但它仍然存在一些需要注意的问题。 饿汉模式 //饿汉模式单例模式
//此处保证Singleton这个类只能创建出一个实例
class Singleton{//在此处先把这个实例给创建出来private static Singleton instance new Singleton();//获取这个唯一实例public static SingletongetInstance() {return instance;}//为了避免Singleton类不小心被复制出多份来//把构造方法设为private在类外面就无法通过new的方式来创建这个Singleton实例了private Singleton() { }}public class ThreadDemo6 {public static void main (String[] args) {Singletons1 Singleton.getInstance();Singletons2 Singleton.getInstance();System.out.println(s1s2);}
} 懒汉模式
//懒汉模式
class SingletonLazy{// 饿汉 与 懒汉 的 根本区别在这里private static SingletonLazy instance null;public static SingletonLazygetInstance() {if (instance null) {instance new SingletonLazy ();}return instance;}private SingletonLazy() {};}public class ThreadDemo7 {public static void main (String[] args) {SingletonLazys1 SingletonLazy.getInstance();SingletonLazys2 SingletonLazy.getInstance();System.out.println(s1s2);}
} 懒汉模式中有一个new的操作这里就可能造成线程安全问题而饿汉模式中只有读的操作所以是线程安全的。 懒汉模式的线程不安全 是因为读操作、比较、写操作不是原子性的。解决的办法就是将这三个操作上锁使其变成原子性的。 在懒汉模式中实例化对象这个步骤可分为下图中的三步 不过也是有办法解决的volatilevolatile有两个功能1解决内存可见性2禁止指令重排序。 或者使用 synchronized 来解决指令重排序问题。
//懒汉模式
classSingletonLazy{private volatile static SingletonLazy instance null;public static SingletonLazy getInstance () {if (instance null ) { //外层这个if 是判断是否加锁synchronized (SingletonLazy.class) {if (instance null) { // 内层这个if 是判断是否实例化对象instance new SingletonLazy();}}}return instance;}private SingletonLazy () {};
}public class ThreadDemo7 {public static void main (String[] args) {SingletonLazys1 SingletonLazy.getInstance();SingletonLazys2 SingletonLazy.getInstance();System.out.println(s1 s2);}
}
针对上面代码中提一个问题既然外层的if已经判断为null了 又有加锁操作是否可以将内存的判断删掉呢 答假设有t1、t2两个线程两个线程都执行到了外层的if语句并且判断都为null但是呢t1线程比t2线程略微快那么一点儿t1线程先申请到了锁所以t2线程就只能线程阻塞了等到t1线程执行完毕后已经实例化了对象此时t2线程再去执行这时的内层if语句就会将t2线程拦下。所以说两个判断语句一个都不能少。 这里还是有一个问题 比如t1线程通过synchronized已经对实例化操作进行加锁了其他线程又如何将执行到一半的t1线程给切换走呢 答线程加锁并不是说这个线程就一直占用cpu只是其他线程执行被上锁的代码时会阻塞但是线程的切换调度还是照常进行的并不会因为加锁而改变。意思就是已经上锁了你的就是你的别人拿不走但是你先别着急我的这个任务优先级更高急需执行所以你就先阻塞一下。然而问题就是出现在这里我t1线程执行到一半了instance已经是非null了但是还没有构造出对象。结果阻塞了然后其他线程刚好在t1阻塞这个期间执行到了第一个if语句发现instance不为null结果就直接返回了instance这个就导致了instance引用指向的对象不完整引发后续问题。 什么是阻塞队列 什么是高内聚 低耦合 答高内聚这是一个软件工程中的重要概念它是判断软件设计优劣的标准之一。具体来说高内聚是指模块内部的元素关联性非常强以至于模块的单一性非常显著。理想情况下一个模块应尽可能独立地完成某个特定的功能。 在面向对象的设计中高内聚低耦合是一个重要的设计原则其主要目标是增强程序模块的可重用性和移植性。如果一个模块的内部实现过于复杂可能会影响其可重用性和移植性。例如如果一个模块需要被各种场景引用那么代码的质量可能会变得非常脆弱这种情况下建议将该模块拆分为多个独立的模块。 总的来说高内聚是强调模块功能的独立性和完整性而低耦合则是强调模块之间的相互独立性它们共同构成了软件设计的重要原则。 阻塞队列是一种在多线程编程中经常使用的线程同步工具它的主要功能是控制生产者和消费者之间的数据流量。阻塞队列的“阻塞”特性带来了几个显著的优点 1. 内存消耗可控当队列容量有限时内存消耗也会受到限制防止过度消耗系统资源。 2. 平衡生产者和消费者速度阻塞功能使得生产者和消费者两端的能力得以平衡。当有任何一端速度过快时阻塞队列便会把过快的速度限制下来。 3. 自动线程阻塞与唤醒在队列中没有数据的情况下消费者端的所有线程都会被自动阻塞挂起直到有数据放入队列。这样的机制减少了手动管理线程的复杂性。 4. 指定超时等待在获取元素时如果队列为空线程可以等待特定的超时时间。如果在超时时间内有数据加入队列线程将继续执行否则可以选择放弃等待或采取其他补救措施。 5. 缓冲区长度可调节一般的队列只能是有限长度的缓冲区一旦超出缓冲长度就无法保留了。当阻塞队列满时阻塞队列会通过阻塞保留住当前想要继续入队的任务。 总体而言阻塞队列通过其阻塞特性不仅使线程间的通信更加高效而且减少了程序员需要处理的并发问题大大提高了程序的稳定性和可靠性。 阻塞队列为生产者消费者模型 带来了两个好处 1解耦合 简单理解就是现在有AB两个程序其中任何一个程序崩了都会导致另一个程序的崩溃这种就是高耦合现象处处受其他程序掣肘。 阻塞队列的出现就是来降低两个程序之间的耦合将AB程序之间的信息交流通过阻塞队列来实现这样的话任何一个程序挂了但是阻塞队列还好着另一个程序还是可以从队里中拿到其的请求。 2削峰填谷 阻塞队列的削峰填谷是一个在多线程编程中常用的术语主要用于描述阻塞队列在处理并发任务时的一种重要功能。 1. 削峰这是指当并发任务的数量过多以至于系统无法及时处理时阻塞队列可以起到缓冲的作用避免系统因为瞬时的大量任务而崩溃。阻塞队列相当于一个缓冲区平衡了生产者和消费者的处理能力。 2. 填谷当并发任务的数量较少时阻塞队列还可以存储这些暂时没有处理的任务等到后续有新的任务到来时再一起处理。这样可以避免系统的空闲资源浪费提高了系统的处理效率。 阻塞队列的实现 //自己实现阻塞队列
//此处不考虑泛型 直接使用 int 来表示class MyBlockingQueue {private int[] items new int[1000];private int head 0; // 头指针private int tail 0; // 尾指针private int size 0; // 记录阻塞队列中元素的个数//入队列public void put(int value) throws InterruptedException {synchronized(this) {//在这里进行循环等待因为 wait 可能被打断。while (size items.length) {//队列满了不能继续插入this.wait();// 自动阻塞等待出队列代码消费者的 唤醒}//数组实现循环队列的处理items[tail] value;tail;//求余数 是一种解决循环数组的方法//tail tail % items.length;//也可以进行一个判断 来解决//相比求余数判断语句的解决方式更容易看懂。 并且这种代码的效率可能更高。if (tail items.length) {tail 0;}size;// 当前队列不为空了唤醒 正在阻塞等待 的出队列程序消费者线程this.notify();}}// 出队列public Integer take() throws InterruptedException {int result 0;synchronized(this) {//这里也是循环等待做同样的处理while (size 0) {//队列为空 无法取出数值// 自动阻塞等待入队列程序生产者线程的唤醒this.wait();}result items[head];head;if (head items.length) {head 0;}size--;// 此时队列中 不是满着的 唤醒 入队列程序生产者线程this.notify();}return result;}//1 先要保证线程安全}public class ThreadDemo9 {public static void main(String[] args) {MyBlockingQueue queue new MyBlockingQueue();//消费者线程Thread customer new Thread(() - {while(true) {Integer result null;try {result queue.take();} catch (InterruptedException e) {e.printStackTrace();}System.out.println(消费元素 result);}});//生产者线程Thread producter new Thread(() - {int count 0;while(true) {try {queue.put(count);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(生产元素 count);count;try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}});customer.start();producter.start();}
} 我是专注学习的章鱼哥~