java多线程应用问题

2025/05/04 Java 共 6995 字,约 20 分钟

循环打印ABC问题

题目:有三个线程分别打印A、B、C,请用多线程编程实现,在屏幕打印10次ABC

整体思路:该问题为三个线程的同步唤醒机制即ThreadA->ThreadB->ThreadC->ThreadA循环执行三个线程。

synchronized+wait/notify

基本思路就是线程A、线程B、线程C三个线程同时启动,因为变量num的初始值为0,所以线程B或线程C拿到锁后,进入while()循环,然后执行wait()方法,线程线程阻塞,释放锁。只有线程A拿到锁后,不进入while()循环,执行num++,打印字符A,最后唤醒线程B和线程C。此时num值为1,只有线程B拿到锁后,不被阻塞,执行num++,打印字符B,最后唤醒线程A和线程C,后面以此类推。

wait,notify都类似condition,不符合就一直wait,然后要notifyAll,因为可能多个等,一个线程可能持续等多次,然后没notify。


class Wait_Notify_ACB {
    private int num;
    private static final Object LOCK = new Object();

    private void printABC(int targetNum) {
        for (int i = 0; i < 100; i++) {
            synchronized (LOCK) {
                while (num % 3 != targetNum) {
                    try {
                        LOCK.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                num++;
                System.out.print(Thread.currentThread().getName());
                LOCK.notifyAll();
            }
        }
    }

    public static void main(String[] args) {
        Wait_Notify_ACB wait_notify_acb = new Wait_Notify_ACB();
        new Thread(() -> {
            wait_notify_acb.printABC(0);
        }, "A").start();
        new Thread(() -> {
            wait_notify_acb.printABC(1);
        }, "B").start();
        new Thread(() -> {
            wait_notify_acb.printABC(2);
        }, "C").start();
    }
}

Semaphore

信号量,类似golang的channel来实现。0长度的阻塞队列

class SemaphoreABC {

    private static Semaphore s1 = new Semaphore(1); //因为先执行线程A,所以这里设s1的计数器为1
    private static Semaphore s2 = new Semaphore(0);
    private static Semaphore s3 = new Semaphore(0);


    private void printABC(Semaphore currentThread, Semaphore nextThread) {
        for (int i = 0; i < 10; i++) {
            try {
                currentThread.acquire();       //阻塞当前线程,即信号量的计数器减1为0
                System.out.print(Thread.currentThread().getName());
                nextThread.release();          //唤醒下一个线程,即信号量的计数器加1

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
        SemaphoreABC printer = new SemaphoreABC();
        new Thread(() -> {
            printer.printABC(s1, s2);
        }, "A").start();
        Thread.sleep(10);
        new Thread(() -> {
            printer.printABC(s2, s3);
        }, "B").start();
        Thread.sleep(10);
        new Thread(() -> {
            printer.printABC(s3, s1);
        }, "C").start();
    }
}

ReentrantLock

重入锁。一个condition. condition的signalAll唤醒了所有的,但其实不是所有的都需要唤醒,可以拆成3个,在后续


class Wait_Notify_ACB {
    private int num;
    private static final Lock lock = new ReentrantLock();
    private static final Condition condition = lock.newCondition();

    private void printABC(int targetNum) {
        for (int i = 0; i < 100; i++) {
            lock.lock();
            try {
                while (num % 3 != targetNum) {
                    condition.await();
                }
                num++;
                System.out.print(Thread.currentThread().getName());
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                condition.signalAll();
                lock.unlock();
            }
        }
    }

    public static void main(String[] args) {
        Wait_Notify_ACB wait_notify_acb = new Wait_Notify_ACB();
        new Thread(() -> {
            wait_notify_acb.printABC(0);
        }, "A").start();
        new Thread(() -> {
            wait_notify_acb.printABC(1);
        }, "B").start();
        new Thread(() -> {
            wait_notify_acb.printABC(2);
        }, "C").start();
    }
}

Reentrantlock + 3个condition

这里没维护变量,因此3个condition是分开的。也可以维护变量来判断。唤醒只用signal是因为等待的线程不会超过1个。

class Solution {
    static Lock lock = new ReentrantLock();
    Condition pre, nxt;
    String val;

    Solution(Condition pre, Condition nxt, String val) {
        this.pre = pre;
        this.nxt = nxt;
        this.val = val;
    }

    void run() {
        for (int i = 0; i < 100; i++) {
            lock.lock();
            try {
                pre.await();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.print(val);
            nxt.signal();
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        Condition a = lock.newCondition();
        Condition b = lock.newCondition();
        Condition c = lock.newCondition();
        new Thread(() -> {
            new Solution(a, b, "A").run();
        }).start();
        new Thread(() -> {
            new Solution(b, c, "B").run();
        }).start();
        new Thread(() -> {
            new Solution(c, a, "C").run();
        }).start();
        lock.lock();
        try {
            a.signal();
        } finally {
            lock.unlock();
        }
    }
}

CyclicBarrier

每次到达一个点,就开始判断打印哪个字母,然后接着往后移动。推荐


class Solution {
    static Integer state = 0;
    static Map<Integer, String> map = Map.of(0, "A", 1, "B", 2, "C");

    public static void main(String[] args) {
        CyclicBarrier barrier = new CyclicBarrier(3, () -> {
            int t = state % 3;
            System.out.print(map.get(t));
            state += 1;
        });
        Runnable runnable = () -> {
            for (int i = 0; i < 300; i++) {
                try {
                    barrier.await();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        };
        new Thread(runnable).start();
        new Thread(runnable).start();
        new Thread(runnable).start();
    }
}

Option2. 线程1 有3个cyclicBarrier, 线程2有两个,线程3有3个。

class Solution {
    static Integer state = 0;
    static Map<Integer, String> map = Map.of(0, "A", 1, "B", 2, "C");

    public static void main(String[] args) {
        CyclicBarrier b1 = new CyclicBarrier(1, () -> {
            System.out.print("A");
        });
        CyclicBarrier b2 = new CyclicBarrier(2, () -> {
            System.out.print("B");
        });
        CyclicBarrier b3 = new CyclicBarrier(3, () -> {
            System.out.print("C");
        });
        new Thread(() -> {
            try {
                for (int i = 0; i < 100; i++) {
                    b1.await();
                    b2.await();
                    b3.await();
                }

            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }).start();
        new Thread(() -> {
            try {
                for (int i = 0; i < 100; i++) {
                    b2.await();
                    b3.await();
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }).start();
        new Thread(() -> {
            try {
                for (int i = 0; i < 100; i++) {
                    b3.await();
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }).start();
    }
}

阻塞队列

class Handler implements Runnable {
    final SynchronousQueue<Integer> pre, nxt;
    final String val;
    final boolean last;

    Handler(SynchronousQueue<Integer> pre, SynchronousQueue<Integer> nxt, String val, boolean last) {
        this.pre = pre;
        this.nxt = nxt;
        this.val = val;
        this.last = last;
    }

    public void run() {
        for (int i = 0; i < 100; i++) {
            try {
                this.pre.take();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.print(this.val + i);
            if (this.last && i == 99) {
                break;
            }
            this.nxt.offer(0);
        }
    }
}

class Solution {
    public static void main(String[] args) throws InterruptedException {
        SynchronousQueue<Integer> a = new SynchronousQueue();
        SynchronousQueue<Integer> b = new SynchronousQueue();
        SynchronousQueue<Integer> c = new SynchronousQueue();
        new Thread(new Handler(a, b, "A", false)).start();
        new Thread(new Handler(b, c, "B", false)).start();
        new Thread(new Handler(c, a, "C", true)).start();
        a.put(0);
        Thread.sleep(1000);
    }
}

生产者消费者

模拟顾客,厨师,服务员。顾客下单给厨师,厨师做好菜给服务员,服务员来上菜。



class Person {
    String name = "customer";
}

class Customer extends Person {
    public Customer() {
        this.name = "customer";
    }
}

class Cook extends Person {
}

class Waiter extends Person {
}

class Menu {
    final Customer customer;
    final List<String> foodNames;

    Menu(Customer customer, List<String> foodNames) {
        this.customer = customer;
        this.foodNames = foodNames;
    }
}

class Food {
    final Menu menu;

    Food(Menu menu) {
        this.menu = menu;
    }
}

class Solution {
    static List<Customer> customers = new ArrayList<>();
    static Cook cook = new Cook();
    static List<Waiter> waiters = new ArrayList<>();
    static BlockingQueue<Menu> orders = new LinkedBlockingQueue<>(10);
    static BlockingQueue<Food> foods = new LinkedBlockingQueue<>(10);

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            customers.add(new Customer());
        }
        for (int i = 0; i < 5; i++) {
            waiters.add(new Waiter());
        }
        for (Customer customer : customers) {
            new Thread(() -> {
                try {
                    orders.put(new Menu(customer, new ArrayList<>()));
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }).start();
        }
        for (Waiter waiter : waiters) {
            new Thread(() -> {
                while (true) {
                    try {
                        Food food = foods.take();
                        System.out.println(waiter + " 上菜 " + food + " 给顾客 " + food.menu.customer);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }).start();
        }
        new Thread(() -> {
            while (true) {
                try {
                    Menu menu = orders.take();
                    Food food = new Food(menu);
                    System.out.println(cook + " 处理食物");
                    foods.put(food);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }).start();
        Thread.sleep(1000);
        System.out.println("done");
    }
}

Search

    Table of Contents