其他(也很重要!)

@[toc] | 题目 | 备注 | | ------------------------ | ---------------------- | | 多线程循环打印(补充题) | 必会多线程题 | | 手写死锁(补充题) | 且需要了解怎么解开死锁 | | 手写单例(补充题) | 必会双检锁写法 | ## 三个线程 T1、T2、T3,如何让他们(循环)按序打印 ABC ![img](https://cs-wiki.oss-cn-shanghai.aliyuncs.com/img/image-20220716183019300.png) ### 方案 1:synchronized ```java class Foo { // 锁对象 private Object obj; // 输出顺序 private int index; public Foo() { obj = new Object(); index = 1; } public void first(Runnable printFirst) throws InterruptedException { synchronized(obj) { while (index != 1) { obj.wait(); } // printFirst.run() outputs "first". Do not change or remove this line. printFirst.run(); index ++; obj.notifyAll(); } } public void second(Runnable printSecond) throws InterruptedException { synchronized(obj) { while (index != 2) { obj.wait(); } // printSecond.run() outputs "second". Do not change or remove this line. printSecond.run(); index ++; obj.notifyAll(); } } public void third(Runnable printThird) throws InterruptedException { synchronized(obj) { while (index != 3) { obj.wait(); } // printThird.run() outputs "third". Do not change or remove this line. printThird.run(); index ++; obj.notifyAll(); } } } ---- // 调用代码应该是这样的: public static void main (String[] args) { Foo foo = new Foo(); new Thread(() -> { foo.first(); }, "ThreadA").start(); new Thread(() -> { foo.first(); }, "ThreadB").start(); new Thread(() -> { foo.first(); }, "ThreadC").start(); } ``` ### 方法 2:Lock ```java class Foo { // 锁 private Lock lock; // 输出顺序 private int index; private Condition condition; public Foo() { lock = new ReentrantLock(); index = 1; condition = lock.newCondition(); } public void first(Runnable printFirst) throws InterruptedException { lock.lock(); try { while (index != 1) { condition.await(); } // printFirst.run() outputs "first". Do not change or remove this line. printFirst.run(); index ++; condition.signalAll(); } catch (Exception e) { e.printStackTrace(); } lock.unlock(); } public void second(Runnable printSecond) throws InterruptedException { lock.lock(); try { while (index != 2) { condition.await(); } // printSecond.run() outputs "second". Do not change or remove this line. printSecond.run(); index ++; condition.signalAll(); } catch (Exception e) { e.printStackTrace(); } lock.unlock(); } public void third(Runnable printThird) throws InterruptedException { lock.lock(); try { while (index != 3) { condition.await(); } // printThird.run() outputs "second". Do not change or remove this line. printThird.run(); index ++; condition.signalAll(); } catch (Exception e) { e.printStackTrace(); } lock.unlock(); } } ``` ### 方案 3:AtomicInteger ```java class Foo { private AtomicInteger firstJobDone; private AtomicInteger secondJobDone; public Foo() { firstJobDone = new AtomicInteger(0); secondJobDone = new AtomicInteger(0); } public void first(Runnable printFirst) throws InterruptedException { // printFirst.run() outputs "first". Do not change or remove this line. printFirst.run(); firstJobDone.incrementAndGet(); } public void second(Runnable printSecond) throws InterruptedException { while (firstJobDone.get() != 1) { // waiting for the first job to be done } // printSecond.run() outputs "second". Do not change or remove this line. printSecond.run(); secondJobDone.incrementAndGet(); } public void third(Runnable printThird) throws InterruptedException { while (secondJobDone.get() != 1) { } // printThird.run() outputs "third". Do not change or remove this line. printThird.run(); } } ``` ### 方案 4:CountDownLatch ```java class Foo { private CountDownLatch countDownLatch1; private CountDownLatch countDownLatch2; public Foo() { countDownLatch1 = new CountDownLatch(1); countDownLatch2 = new CountDownLatch(1); } public void first(Runnable printFirst) throws InterruptedException { // printFirst.run() outputs "first". Do not change or remove this line. printFirst.run(); countDownLatch1.countDown(); } public void second(Runnable printSecond) throws InterruptedException { // 等待计数器归零再向下执行 countDownLatch1.await(); // printSecond.run() outputs "second". Do not change or remove this line. printSecond.run(); countDownLatch2.countDown(); } public void third(Runnable printThird) throws InterruptedException { // 等待计数器归零再向下执行 countDownLatch2.await(); // printThird.run() outputs "third". Do not change or remove this line. printThird.run(); } } ``` ### 方案 5:Semaphore ```java import java.util.concurrent.Semaphore; class Foo { Semaphore semaphore12, semaphore23; public Foo() { //初始的允许请求均设为0 semaphore12 = new Semaphore(0); semaphore23 = new Semaphore(0); } public void first(Runnable printFirst) throws InterruptedException { // printFirst.run() outputs "first". Do not change or remove this line. printFirst.run(); //释放一个12的信号量 semaphore12.release(); } public void second(Runnable printSecond) throws InterruptedException { // 获取一个 12 的信号量,没有则阻塞 semaphore12.acquire(); // printSecond.run() outputs "second". Do not change or remove this line. printSecond.run(); //释放一个23的信号量 semaphore23.release(); } public void third(Runnable printThird) throws InterruptedException { //获取一个23的信号量,没有则阻塞 semaphore23.acquire(); // printThird.run() outputs "third". Do not change or remove this line. printThird.run(); } } ``` ### 方案 6:SynchronousQueue ```java class Foo { private BlockingQueue<Integer> blockingQueue1; private BlockingQueue<Integer> blockingQueue2; public Foo() { blockingQueue1 = new SynchronousQueue<>(); blockingQueue2 = new SynchronousQueue<>(); } public void first(Runnable printFirst) throws InterruptedException { // printFirst.run() outputs "first". Do not change or remove this line. printFirst.run(); blockingQueue1.put(1); } public void second(Runnable printSecond) throws InterruptedException { // 如果 blockingQueue1 里面没东西的话当前线程会阻塞 blockingQueue1.take(); // printSecond.run() outputs "second". Do not change or remove this line. printSecond.run(); blockingQueue2.put(1); } public void third(Runnable printThird) throws InterruptedException { // 如果 blockingQueue2 里面没东西的话当前线程会阻塞 blockingQueue2.take(); // printThird.run() outputs "third". Do not change or remove this line. printThird.run(); } } ``` ## 写一个死锁 ## 手写单例模式 ### 饿汉式(线程安全) ```java public class EagerSingleton { private static final EagerSingleton instance = new EagerSingleton(); private EagerSingleton() {} public static EagerSingleton getInstance() { return instance; } } ``` **特点**:类加载时立即初始化,线程安全但可能浪费内存。 ### 懒汉式(线程不安全) ```java public class LazySingleton { private static LazySingleton instance; private LazySingleton() {} public static LazySingleton getInstance() { if (instance == null) { instance = new LazySingleton(); } return instance; } } ``` **特点**:延迟加载,但多线程环境下可能创建多个实例。 ### 同步懒汉式(线程安全) ```java public class SyncLazySingleton { private static SyncLazySingleton instance; private SyncLazySingleton() {} public static synchronized SyncLazySingleton getInstance() { if (instance == null) { instance = new SyncLazySingleton(); } return instance; } } ``` **特点**:通过`synchronized`保证线程安全,但性能较差。 ### 双重检查锁(DCL,线程安全) ```java public class DCLSingleton { private static volatile DCLSingleton instance; private DCLSingleton() {} public static DCLSingleton getInstance() { if (instance == null) { synchronized (DCLSingleton.class) { if (instance == null) { instance = new DCLSingleton(); } } } return instance; } } ``` **特点**:延迟加载 + 高效线程安全,需`volatile`防止指令重排序。 ### 静态内部类(线程安全) ```java public class InnerClassSingleton { private InnerClassSingleton() {} private static class Holder { private static final InnerClassSingleton instance = new InnerClassSingleton(); } public static InnerClassSingleton getInstance() { return Holder.instance; } } ``` **特点**:利用类加载机制保证线程安全,延迟加载且无锁。 ### 枚举(线程安全,防反射/序列化攻击) ```java public enum EnumSingleton { INSTANCE; public void doSomething() { // 业务方法 } } ``` **特点**:JVM 保证单例,天然防反射、序列化破坏,推荐使用。 ### 对比总结 | 实现方式 | 线程安全 | 延迟加载 | 防反射 | 防序列化 | 性能 | | :--------- | :------- | :------- | :----- | :------- | :--- | | 饿汉式 | ✔️ | ❌ | ❌ | ❌ | 高 | | 懒汉式 | ❌ | ✔️ | ❌ | ❌ | 高 | | 同步懒汉式 | ✔️ | ✔️ | ❌ | ❌ | 低 | | 双重检查锁 | ✔️ | ✔️ | ❌ | ❌ | 中 | | 静态内部类 | ✔️ | ✔️ | ❌ | ❌ | 高 | | 枚举 | ✔️ | ❌ | ✔️ | ✔️ | 高 | ### 最佳实践 - 需要延迟加载 → **静态内部类** - 需要防反射/序列化 → **枚举** - 旧版本兼容场景 → **双重检查锁**