1. synchronized 关键字
- 基本用法和特点:用于实现线程同步,保证同一时刻仅有一个线程能访问被同步的代码块或方法。既可以修饰方法,也能修饰代码块 ,如 synchronized (锁对象) { } ,其中锁对象可以是任意对象。
- 可重入性:同一线程持有锁时,可再次进入被该锁同步的区域。比如递归方法被 synchronized 修饰,递归调用时线程无需重新获取锁。
- 死锁问题
- 死锁场景:一个线程连续两次获取同一把锁;两个线程交叉获取锁(线程1持有锁A,等待锁B,线程2持有锁B,等待锁A );多个线程竞争有限数量的锁(如哲学家就餐问题 ) 。
- 死锁必要条件:互斥、不可抢占、请求和保持、循环等待 。
- 代码示例
public class SynchronizedExample {
private static final Object lock = new Object();
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
synchronized (lock) {
System.out.println("Thread 1 acquired the lock");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (lock) {
System.out.println("Thread 2 acquired the lock");
}
});
thread1.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread2.start();
}
}
2. volatile 关键字
- 作用:解决内存可见性问题,禁止编译器对该变量相关操作进行优化,确保不同线程对该变量的读取为最新值。
- 代码示例
public class VolatileExample {
private static volatile boolean flag = false;
public static void main(String[] args) {
new Thread(() -> {
while (!flag) {
// 等待flag变为true
}
System.out.println("Flag is true, thread is running");
}).start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = true;
}
}
3. wait 和 notify 方法
- 所属及功能:是 Object 类的方法,用于协调线程执行顺序。 wait 使当前线程进入等待状态并释放锁; notify 唤醒在同一个对象上等待的某个线程, notifyAll 唤醒所有等待线程 。
- 使用要求: wait 需在 synchronized 代码块内使用,否则会抛出 IllegalMonitorStateException 异常。
- 代码示例
public class WaitNotifyExample {
private static final Object lock = new Object();
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
synchronized (lock) {
try {
System.out.println("Thread 1 is waiting");
lock.wait();
System.out.println("Thread 1 is notified");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (lock) {
System.out.println("Thread 2 is notifying");
lock.notify();
}
});
thread1.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread2.start();
}
}
4. 单例模式 - 懒汉式
- 普通懒汉式(线程不安全):在第一次调用 getInstance 方法时创建实例,在多线程环境下可能创建多个实例。
- 线程安全的懒汉式(双重检查锁定):通过双重检查( if (instance == null) )和 synchronized 关键字保证线程安全,延迟实例创建。使用 volatile 修饰实例变量防止指令重排,避免对象未完成初始化就被其他线程获取使用。
- 代码示例
- 普通懒汉式单例(线程不安全)
public class SingletonLazyUnsafe {
private static SingletonLazyUnsafe instance;
private SingletonLazyUnsafe() {}
public static SingletonLazyUnsafe getInstance() {
if (instance == null) {
instance = new SingletonLazyUnsafe();
}
return instance;
}
}
- 线程安全的懒汉式单例(双重检查锁定)
public class SingletonLazySafe {
private static volatile SingletonLazySafe instance;
private static final Object locker = new Object();
private SingletonLazySafe() {}
public static SingletonLazySafe getInstance() {
if (instance == null) {
synchronized (locker) {
if (instance == null) {
instance = new SingletonLazySafe();
}
}
}
return instance;
}
}
5. 指令重排序
- 概念:属于编译器优化手段,在确保逻辑一致的前提下调整代码顺序以提高效率,但在多线程环境下可能引发线程安全问题。例如创建对象操作(申请内存空间、初始化、将内存地址保存到引用变量 )可能因指令重排导致顺序改变,进而引发问题。
6. BlockingQueue
javaimport java.util.Arrays;public class CustomBlockingQueue<T> {private T[] queue;private int head;private int tail;private int size;private static final int DEFAULT_CAPACITY = 10;private final Object lock = new Object();public CustomBlockingQueue() {this(DEFAULT_CAPACITY);}public CustomBlockingQueue(int capacity) {queue = (T[]) new Object[capacity];head = 0;tail = 0;size = 0;}public void put(T item) throws InterruptedException {synchronized (lock) {while (size == queue.length) {lock.wait();}queue[tail] = item;tail = (tail + 1) % queue.length;size++;lock.notify();}}public T take() throws InterruptedException {synchronized (lock) {while (size == 0) {lock.wait();}T item = queue[head];head = (head + 1) % queue.length;size--;lock.notify();return item;}}}
7. 线程池( ThreadPoolExecutor )
javaimport java.util.concurrent.*;public class ThreadPoolExecutorExample {public static void main(String[] args) {ThreadPoolExecutor executor = new ThreadPoolExecutor(2,4,60,TimeUnit.SECONDS,new LinkedBlockingQueue<>(5),new ThreadPoolExecutor.CallerRunsPolicy());for (int i = 0; i < 10; i++) {executor.submit(() -> {try {Thread.sleep(1000);System.out.println("Task executed in thread: " + Thread.currentThread().getName());} catch (InterruptedException e) {e.printStackTrace();}});}executor.shutdown();}}
8. 生产者 - 消费者模型
javaimport java.util.concurrent.BlockingQueue;import java.util.concurrent.LinkedBlockingQueue;class Producer implements Runnable {private BlockingQueue<String> queue;public Producer(BlockingQueue<String> queue) {this.queue = queue;}@Overridepublic void run() {try {queue.put("product1");queue.put("product2");queue.put("product3");} catch (InterruptedException e) {e.printStackTrace();}}}class Consumer implements Runnable {private BlockingQueue<String> queue;public Consumer(BlockingQueue<String> queue) {this.queue = queue;}@Overridepublic void run() {try {System.out.println(queue.take());System.out.println(queue.take());System.out.println(queue.take());} catch (InterruptedException e) {e.printStackTrace();}}}public class ProducerConsumerExample {public static void main(String[] args) {BlockingQueue<String> queue = new LinkedBlockingQueue<>(3);Thread producerThread = new Thread(new Producer(queue));Thread consumerThread = new Thread(new Consumer(queue));producerThread.start();consumerThread.start();try {producerThread.join();consumerThread.join();} catch (InterruptedException e) {e.printStackTrace();}}}
9. 综合复习与面试相关