Java 多线程-经典编程题

  • 手写死锁
  • 手写生产者消费者模型
  • 三个线程顺序打印 ABC
  • 三个线程循环顺序打印 ABC 十次

手写死锁

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
public class DeadLockDemo {
    private static final Object resource1 = new Object(); // 资源1
    private static final Object resource2 = new Object(); // 资源2

    public static void main(String[] args) {
        new Thread(() -> {
            synchronized (resource1) {
                System.out.println(Thread.currentThread().getName() + " 获取资源1");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " 等待资源2");
                synchronized (resource2) {
                    System.out.println(Thread.currentThread().getName() + " 获取资源2");
                }
            }
        }, "线程1").start();

        new Thread(() -> {
            synchronized (resource2) {
                System.out.println(Thread.currentThread().getName() + " 获取资源2");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " 等待资源1");
                synchronized (resource1) {
                    System.out.println(Thread.currentThread().getName() + " 获取资源1");
                }
            }
        }, "线程2").start();
    }
}
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
public class DeadLockDemo {
    public static void main(String[] args) {
        new DeadLockDemo().deadLock();
    }

    private final String A = "A";
    private final String B = "b";

    public void deadLock() {
        Thread t1 = new Thread(() -> {
            synchronized (A) {
                System.out.println(Thread.currentThread().getName() + " 线程获得了锁 A,尝试获取锁 B。");
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (B) {
                }
            }
        }, "t1");

        Thread t2 = new Thread(() -> {
            synchronized (B) {
                System.out.println(Thread.currentThread().getName() + " 线程获得了锁 B,尝试获取锁 A。");
                synchronized (A) {

                }
            }
        }, "t2");

        t1.start();
        t2.start();
    }
}

手写生产者消费者模型

1. 使用 synchronized 和 wait/notify/notifyAll 实现

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
public class ProducerConsumerExample {
    public static void main(String[] args) {
        Queue<Integer> queue = new LinkedList<>();
        int maxSize = 5;

        Thread producer = new Thread(new Producer(queue, maxSize), "Producer");
        Thread consumer = new Thread(new Consumer(queue), "Consumer");

        producer.start();
        consumer.start();
    }
}

class Producer implements Runnable {
    private final Queue<Integer> queue;
    private final int maxSize;

    public Producer(Queue<Integer> queue, int maxSize) {
        this.queue = queue;
        this.maxSize = maxSize;
    }

    @Override
    public void run() {
        int value = 0;
        while (true) {
            synchronized (queue) {
                while (queue.size() == maxSize) {
                    try {
                        queue.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("Producing value: " + value);
                queue.add(value++);
                queue.notifyAll();
            }
        }
    }
}

class Consumer implements Runnable {
    private final Queue<Integer> queue;

    public Consumer(Queue<Integer> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (queue) {
                while (queue.isEmpty()) {
                    try {
                        queue.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("Consuming value: " + queue.remove());
                queue.notifyAll();
            }
        }
    }
}

2. 使用 BlockingQueue 实现

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
public class ProducerConsumerExample {
    public static void main(String[] args) {
        BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(5);

        Thread producer = new Thread(new Producer(queue), "Producer");
        Thread consumer = new Thread(new Consumer(queue), "Consumer");

        producer.start();
        consumer.start();
    }
}

class Producer implements Runnable {
    private final BlockingQueue<Integer> queue;

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

    @Override
    public void run() {
        int value = 0;
        while (true) {
            try {
                System.out.println("Producing value: " + value);
                queue.put(value++);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Consumer implements Runnable {
    private final BlockingQueue<Integer> queue;

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

    @Override
    public void run() {
        while (true) {
            try {
                System.out.println("Consuming value: " + queue.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

三个线程顺序打印 ABC

1. 使用 join() 实现

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
public class OrderedPrintABC {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("A");
        });

        Thread t2 = new Thread(() -> {
            try {
                t1.join();
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("B");
        });

        Thread t3 = new Thread(() -> {
            try {
                t2.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("C");
        });

        t1.start();
        t2.start();
        t3.start();
    }
}

2. 使用线程池的 ExecutorService 顺序执行

1
2
3
4
5
6
7
8
9
public class OrderedPrintABC {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        executor.execute(() -> System.out.println("A"));
        executor.execute(() -> System.out.println("B"));
        executor.execute(() -> System.out.println("C"));
        executor.shutdown();
    }
}

3. 使用 CountDownLatch 实现

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
public class OrderedPrintABC {
    public static void main(String[] args) {
        CountDownLatch latch1 = new CountDownLatch(1);
        CountDownLatch latch2 = new CountDownLatch(1);

        Thread t1 = new Thread(() -> {
            System.out.println("A");
            latch1.countDown();
        });

        Thread t2 = new Thread(() -> {
            try {
                latch1.await();
                System.out.println("B");
                latch2.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread t3 = new Thread(() -> {
            try {
                latch2.await();
                System.out.println("C");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        t1.start();
        t2.start();
        t3.start();
    }
}

4. 使用 synchronized 和 wait/notify/notifyAll 实现

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
public class OrderedPrintABC {
    private static final Object lock = new Object();
    private static int state = 0;

    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            synchronized (lock) {
                while (state % 3 != 0) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("A");
                state++;
                lock.notifyAll();
            }
        });

        Thread t2 = new Thread(() -> {
            synchronized (lock) {
                while (state % 3 != 1) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("B");
                state++;
                lock.notifyAll();
            }
        });

        Thread t3 = new Thread(() -> {
            synchronized (lock) {
                while (state % 3 != 2) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("C");
                state++;
                lock.notifyAll();
            }
        });

        t1.start();
        t2.start();
        t3.start();
    }
}

5. 使用 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
public class OrderedPrintABC {
    private static final ReentrantLock lock = new ReentrantLock();
    private static final Condition condition = lock.newCondition();
    private static int state = 0;

    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            lock.lock();
            try {
                while (state % 3 != 0) {
                    try {
                        condition.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("A");
                state++;
                condition.signalAll();
            } finally {
                lock.unlock();
            }
        });

        Thread t2 = new Thread(() -> {
            lock.lock();
            try {
                while (state % 3 != 1) {
                    try {
                        condition.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("B");
                state++;
                condition.signalAll();
            } finally {
                lock.unlock();
            }
        });

        Thread t3 = new Thread(() -> {
            lock.lock();
            try {
                while (state % 3 != 2) {
                    try {
                        condition.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("C");
                state++;
                condition.signalAll();
            } finally {
                lock.unlock();
            }
        });

        t1.start();
        t2.start();
        t3.start();
    }
}

三个线程循环顺序打印 ABC 十次

1. 使用 synchronized 和 wait/notify/notifyAll 实现

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
public class PrintABC {
    private static final int PRINT_COUNT = 10;
    private static final int THREAD_COUNT = 3;
    private static volatile int currentCount = 0;

    public static void main(String[] args) {
        Object lock = new Object();
        for (int i = 0; i < THREAD_COUNT; i++) {
            new Thread(new PrintTask(lock, i), String.valueOf((char) ('A' + i))).start();
        }
    }

    private static class PrintTask implements Runnable {
        private final Object lock;
        private final int targetNum;

        public PrintTask(Object lock, int targetNum) {
            this.lock = lock;
            this.targetNum = targetNum;
        }

        @Override
        public void run() {
            for (int i = 0; i < PRINT_COUNT; i++) {
                synchronized (lock) {
                    while (currentCount % THREAD_COUNT != targetNum) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.print(Thread.currentThread().getName());
                    currentCount++;
                    lock.notifyAll();
                }
            }
        }
    }
}

2. 使用 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
public class PrintABC {
    private static int threadCount;
    private static int printCount;
    private static int currentCount = 0;
    private static final Lock lock = new ReentrantLock();
    private static Condition[] conditions;

    public static void main(String[] args) {
        threadCount = 3;
        printCount = 10;
        conditions = new Condition[threadCount];

        for (int i = 0; i < threadCount; i++) {
            conditions[i] = lock.newCondition();
        }

        for (int i = 0; i < threadCount; i++) {
            new Thread(new PrintTask(i), String.valueOf((char) ('A' + i))).start();
        }
    }

    static class PrintTask implements Runnable {
        private final int threadIndex;

        public PrintTask(int threadIndex) {
            this.threadIndex = threadIndex;
        }

        @Override
        public void run() {
            while (true) {
                lock.lock();
                try {
                    if (currentCount >= threadCount * printCount) {
                        break;
                    }
                    while (currentCount % threadCount != threadIndex) {
                        conditions[threadIndex].await();
                    }
                    System.out.print(Thread.currentThread().getName());
                    currentCount++;
                    conditions[(threadIndex + 1) % threadCount].signal();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        }
    }
}
本文作者:
本文链接: https://hgnulb.github.io/blog/2023/59592867
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!