【面试系列】多线程面试题1

204 阅读2分钟

微信公众号:放开我我还能学

分享知识,共同进步!


题目:实现一个容器,包含 add 和 size 两个方法。写两个线程,线程 1 添加 10 个元素到容器中,线程 2 监控元素的个数,当元素个数达到 5 时,线程 2 给出提示。

下面给出 4 种解法

等待通知机制

synchronized

public class WithWaitAndNotify<E> {

    List<E> list = new ArrayList();

    public void add(E e) {
        list.add(e);
    }

    public int size() {
        return list.size();
    }

    public static void main(String[] args) {

        WithWaitAndNotify<Integer> c = new WithWaitAndNotify();

        final Object lock = new Object();

        new Thread(() -> {
            System.out.println("t2启动");
            synchronized (lock) {
                if (c.size() != 5) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("t2结束");
                // 唤醒t1
                lock.notify();
            }
        }, "t2").start();

        new Thread(() -> {
            System.out.println("t1启动");
            synchronized (lock) {
                for (int i = 0; i < 10; i++) {
                    c.add(i);
                    System.out.println("add " + i);
                    if (c.size() == 5) {
                        // 唤醒t2
                        lock.notify();
                        try {
                            // 提前释放锁,让t2执行,否则需要等到t1的所有代码执行完才会释放锁
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }

                    }
                }
            }
        }, "t1").start();
    }
}

Condition

public class WithCondition<E> {

    List<E> list = new ArrayList();

    public void add(E e) {
        list.add(e);
    }

    public int size() {
        return list.size();
    }

    public static void main(String[] args) {

        WithCondition<Integer> c = new WithCondition();

        ReentrantLock lock = new ReentrantLock();
        Condition condition = lock.newCondition();

        new Thread(() -> {
            System.out.println("t2启动");
            lock.lock();
            try {
                if (c.size() != 5) {
                    try {
                        condition.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("t2结束");
                    // 唤醒t1
                    condition.signal();
                }
            } finally {
                lock.unlock();
            }
        }, "t2").start();

        new Thread(() -> {
            System.out.println("t1启动");
            lock.lock();
            try {
                for (int i = 0; i < 10; i++) {
                    c.add(i);
                    System.out.println("add " + i);
                    if (c.size() == 5) {
                        // 唤醒t2
                        condition.signal();
                        try {
                            // 提前释放锁,让t2执行,否则需要等到t1的所有代码执行完才会释放锁
                            condition.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }

                    }
                }
            } finally {
                lock.unlock();
            }
        }, "t1").start();
    }
}

CountDownLatch

public class WithCountDownLatch<E> {

    List<E> list = new ArrayList();

    public void add(E e) {
        list.add(e);
    }

    public int size() {
        return list.size();
    }

    public static void main(String[] args) {

        WithCountDownLatch<Object> c = new WithCountDownLatch<>();

        CountDownLatch latch1 = new CountDownLatch(1);
        CountDownLatch latch2 = new CountDownLatch(1);

        new Thread(() -> {
            System.out.println("t2启动");
            // 一开始就先拴住t2
            try {
                latch2.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("t2结束");
            // t2结束以后唤醒t1
            latch1.countDown();
        }, "t2").start();

        new Thread(() -> {
            System.out.println("t1启动");
            for (int i = 0; i < 10; i++) {
                c.add(i);
                System.out.println("add " + i);
                if (c.size() == 5) {
                    try {
                        // 先唤醒t2
                        latch2.countDown();
                        // 然后拴住t1自己
                        latch1.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }
            }
        }, "t1").start();
    }
}

LockSupport

public class WithLockSupport<E> {

    List<E> list = new ArrayList();

    public void add(E e) {
        list.add(e);
    }

    public int size() {
        return list.size();
    }

    static Thread t1 = null, t2 = null;

    public static void main(String[] args) {

        WithLockSupport<Integer> c = new WithLockSupport<>();

        t1 = new Thread(() -> {
            System.out.println("t1启动");
            for (int i = 0; i < 10; i++) {
                c.add(i);
                System.out.println("add " + i);

                if (c.size() == 5) {
                    // 先唤醒t2
                    LockSupport.unpark(t2);
                    // 然后阻塞t1自己
                    LockSupport.park();
                }
            }
        }, "t1");

        t2 = new Thread(() -> {
            System.out.println("t2启动");
            // 阻塞t2自己
            LockSupport.park();
            System.out.println("t2结束");
            // t2结束以后唤醒t1
            LockSupport.unpark(t1);
        }, "t2");

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

本文使用 mdnice 排版