1. 多线程交替打印ABC

1.1 基于Synchronized实现

每个线程都抢占同一把锁,根据公有的变量判断是否能打印,否则阻塞

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
public class PrintABC {
private static final int MAX_PRINT_COUNT = 10; // 循环打印次数
private static int state = 0; // 线程状态,0表示打印A,1表示打印B,2表示打印C

public static void main(String[] args) {
Object lock = new Object();

Thread threadA = new Thread(() -> {
for (int i = 0; i < MAX_PRINT_COUNT; i++) {
synchronized (lock) {
while (state % 3 != 0) { // 轮到A打印
try {
lock.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
System.out.print("A");
state++;
lock.notifyAll();
}
}
});

Thread threadB = new Thread(() -> {
for (int i = 0; i < MAX_PRINT_COUNT; i++) {
synchronized (lock) {
while (state % 3 != 1) { // 轮到B打印
try {
lock.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
System.out.print("B");
state++;
lock.notifyAll();
}
}
});

Thread threadC = new Thread(() -> {
for (int i = 0; i < MAX_PRINT_COUNT; i++) {
synchronized (lock) {
while (state % 3 != 2) { // 轮到C打印
try {
lock.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
System.out.print("C");
state++;
lock.notifyAll();
}
}
});

// 启动三个线程
threadA.start();
threadB.start();
threadC.start();
}
}

1.2 基于ReentrantLock和Condition实现

一个线程绑定同一个ReentrantLock的不同Condition,顺序唤醒

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class PrintABCWithLock {
private static final int MAX_PRINT_COUNT = 10; // 循环打印次数
private static int state = 0; // 线程状态,0表示打印A,1表示打印B,2表示打印C

public static void main(String[] args) {
Lock lock = new ReentrantLock();
Condition conditionA = lock.newCondition();
Condition conditionB = lock.newCondition();
Condition conditionC = lock.newCondition();

Thread threadA = new Thread(() -> {
for (int i = 0; i < MAX_PRINT_COUNT; i++) {
lock.lock();
try {
while (state % 3 != 0) {
conditionA.await(); // 等待轮到A打印
}
System.out.print("A");
state++;
conditionB.signal(); // 通知线程B
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.unlock();
}
}
});

Thread threadB = new Thread(() -> {
for (int i = 0; i < MAX_PRINT_COUNT; i++) {
lock.lock();
try {
while (state % 3 != 1) {
conditionB.await(); // 等待轮到B打印
}
System.out.print("B");
state++;
conditionC.signal(); // 通知线程C
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.unlock();
}
}
});

Thread threadC = new Thread(() -> {
for (int i = 0; i < MAX_PRINT_COUNT; i++) {
lock.lock();
try {
while (state % 3 != 2) {
conditionC.await(); // 等待轮到C打印
}
System.out.print("C");
state++;
conditionA.signal(); // 通知线程A
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.unlock();
}
}
});

// 启动三个线程
threadA.start();
threadB.start();
threadC.start();
}
}

1.3 基于Semaphore实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import java.util.concurrent.Semaphore;

public class PrintABCWithSemaphore {
private static final int MAX_PRINT_COUNT = 10; // 循环打印次数

public static void main(String[] args) {
Semaphore semaphoreA = new Semaphore(1); // A线程初始可以运行
Semaphore semaphoreB = new Semaphore(0); // B线程初始阻塞
Semaphore semaphoreC = new Semaphore(0); // C线程初始阻塞

Thread threadA = new Thread(() -> {
for (int i = 0; i < MAX_PRINT_COUNT; i++) {
try {
semaphoreA.acquire(); // 获取许可
System.out.print("A");
semaphoreB.release(); // 通知线程B
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});

Thread threadB = new Thread(() -> {
for (int i = 0; i < MAX_PRINT_COUNT; i++) {
try {
semaphoreB.acquire(); // 获取许可
System.out.print("B");
semaphoreC.release(); // 通知线程C
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});

Thread threadC = new Thread(() -> {
for (int i = 0; i < MAX_PRINT_COUNT; i++) {
try {
semaphoreC.acquire(); // 获取许可
System.out.print("C");
semaphoreA.release(); // 通知线程A
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});

// 启动三个线程
threadA.start();
threadB.start();
threadC.start();
}
}

2. 单例模式

2.1 懒汉

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Singleton {
private static Singleton instance;

private Singleton() {}

public static Singleton getInstance() {

if(instance == null) {
instance = new Singleton();
}
return instance;
}
}

2.2 饿汉

1
2
3
4
5
6
7
8
9
public class Singleton {
private static Singleton instance = new Singleton();

private Singleton() {}

public static Singleton getInstance() {
return instance;
}
}

2.1 双检锁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Singleton {
private static volatile Singleton instance;

private Singleton() {}

public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}

3. 一个线程等待三个并发线程全部执行完再执行

可以使用 CountDownLatch 来实现 3 个线程并发执行,另一个线程等待这三个线程全部执行完再执行的需求。以下是具体的实现步骤:

  • 创建一个 CountDownLatch 对象,并将计数器初始化为 3,因为有 3 个线程需要等待。
  • 创建 3 个并发执行的线程,在每个线程的任务结束时调用 countDown 方法将计数器减 1。
  • 创建第 4 个线程,使用 await 方法等待计数器为 0,即等待其他 3 个线程完成任务。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import java.util.concurrent.CountDownLatch;

public class CountDownLatchExample {
public static void main(String[] args) {
// 创建一个 CountDownLatch,初始计数为 3
CountDownLatch latch = new CountDownLatch(3);

// 创建并启动 3 个并发线程
for (int i = 0; i < 3; i++) {
final int threadNumber = i + 1;
new Thread(() -> {
try {
System.out.println("Thread " + threadNumber + " is working.");
// 模拟线程执行任务
Thread.sleep((long) (Math.random() * 1000));
System.out.println("Thread " + threadNumber + " has finished.");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 任务完成后,计数器减 1
latch.countDown();
}
}).start();
}

// 创建并启动第 4 个线程,等待其他 3 个线程完成
new Thread(() -> {
try {
System.out.println("Waiting for other threads to finish.");
// 等待计数器为 0
latch.await();
System.out.println("All threads have finished, this thread starts to work.");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}

4. 生产者消费者模型

这里假定生产者10s生产一个,消费者4s消费一个

生产者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.util.concurrent.BlockingQueue;

public class Producer implements Runnable {
public BlockingQueue<Integer> queue;

public Producer(BlockingQueue queue) {
this.queue = queue;
}

@Override
public void run() {
while (true) {
try {
Thread.sleep(10000);
queue.add(1);
System.out.println("生产者生产一个产品");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}

消费者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.util.concurrent.BlockingQueue;

public class Consumer implements Runnable {
public BlockingQueue<Integer> queue;

public Consumer(BlockingQueue queue) {
this.queue = queue;
}

@Override
public void run() {
while (true) {
try {
Thread.sleep(4000);
queue.take();
System.out.println("消费者消费一个产品");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}

执行类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class Main {
public static void main(String[] args) {
BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(100);
// 注意生产者消费者需要用构造方法来指定使用同一个阻塞队列
Producer producer = new Producer(queue);
Consumer consumer = new Consumer(queue);
Thread threadA = new Thread(producer);
Thread threadB = new Thread(consumer);
threadA.start();
threadB.start();
}
}

5. JDK动态代理

这里以HelloService为例进行示意

目标类实现的接口HelloService,这个接口目标类和代理类都需要实现

1
2
3
public interface HelloService {
String sayHello();
}

目标类HelloServiceImpl

1
2
3
4
5
public class HelloServiceImpl implements HelloService {
public String sayHello() {
return "Hello, JDK Proxy!";
}
}

代理类MyInvocationHandler,需要实现InvocationHandler接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

// 实现 InvocationHandler 接口的调用处理器
public class MyInvocationHandler implements InvocationHandler {
private Object target;

public MyInvocationHandler(Object target) {
this.target = target;
}

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在目标方法调用前可以添加自己的操作
System.out.println("Before invoking " + method.getName());
Object result = method.invoke(target, args); // 调用目标方法
// 在目标方法调用后可以添加自己的操作
System.out.println("After invoking " + method.getName());
return result;
}
}

测试类Test

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

// 测试类
public class Test {
public static void main(String[] args) {
HelloService target = new HelloServiceImpl();
// 执行代理类构造方法,创建代理类handler对象
InvocationHandler handler = new MyInvocationHandler(target);
// 创建代理类对象,需要传入目标类的ClassLoader和其所实现的所有接口
HelloService proxy = (HelloService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
handler);
String result = proxy.sayHello();
System.out.println(result);
}
}