其他(也很重要!)
@[toc]
| 题目 | 备注 |
| ------------------------ | ---------------------- |
| 多线程循环打印(补充题) | 必会多线程题 |
| 手写死锁(补充题) | 且需要了解怎么解开死锁 |
| 手写单例(补充题) | 必会双检锁写法 |
## 三个线程 T1、T2、T3,如何让他们(循环)按序打印 ABC

### 方案 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 保证单例,天然防反射、序列化破坏,推荐使用。
### 对比总结
| 实现方式 | 线程安全 | 延迟加载 | 防反射 | 防序列化 | 性能 |
| :--------- | :------- | :------- | :----- | :------- | :--- |
| 饿汉式 | ✔️ | ❌ | ❌ | ❌ | 高 |
| 懒汉式 | ❌ | ✔️ | ❌ | ❌ | 高 |
| 同步懒汉式 | ✔️ | ✔️ | ❌ | ❌ | 低 |
| 双重检查锁 | ✔️ | ✔️ | ❌ | ❌ | 中 |
| 静态内部类 | ✔️ | ✔️ | ❌ | ❌ | 高 |
| 枚举 | ✔️ | ❌ | ✔️ | ✔️ | 高 |
### 最佳实践
- 需要延迟加载 → **静态内部类**
- 需要防反射/序列化 → **枚举**
- 旧版本兼容场景 → **双重检查锁**
