多线程面试题

两个线程一个打印奇数一个打印偶数

   private int count = 0;
    private final Object lock = new Object();

    @Test
    public void test() throws InterruptedException {
        Thread even = new Thread(new TurningRunner(), "偶数");
        even.start();
        // 确保偶数线程线先获取到锁
        Thread.sleep(1);
        Thread odd = new Thread(new TurningRunner(), "奇数");
        odd.start();
        even.join();
        odd.join();
    }

    class TurningRunner implements Runnable {
        @Override
        public void run() {
            while (count <= 100) {
                synchronized (lock) {
                    System.out.println(Thread.currentThread().getName() + ": " + count++);
                    lock.notifyAll();
                    try {
                        if (count <= 100) {
                            lock.wait();
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

N个线程顺序循环打印从0至100

通过N个线程顺序循环打印从0至100,如给定N=3。则输出: thread0: 0 thread1: 1 thread2: 2 thread0: 3 thread1: 4

这道题很考察多线程基础。主要在于N个线程循环打印。关键在于如何控制线程的执行顺序,即唤醒特定的线程。之前通过notify()唤醒一个,notifyAll()唤醒全部,但都无法选择特定的线程执行。那如何控制控制线程有序的打印呢?

这里可以用semaphore信号量实现。设置semaphore[]数组,每个线程持有本身的信号量以及上个线程的信号量。对于三个线程abc来说,他们的last信号量对应关系为:

a.last - > semaphores[2]

b.last - > semaphores[0]

c.last - > semaphores[1]

每个线程执行时,会抢占last信号量,如a抢占 semaphores[2],同时释放当前信号量semaphores[0],通知等待队列中的线程b,这时线程b才能抢占通过它的last信号量:semaphores[0],同时再释放semaphores[1],然后唤醒c线程。。依此循环执行。

    int count = 0;
    Thread[] threads;
    Semaphore[] semaphores;

    public void print(int len) throws Exception {
        threads = new Thread[len];
        semaphores = new Semaphore[len];
        for (int i = 0; i < len; i++) {
            semaphores[i] = new Semaphore(1);
            if (i != len - 1) {
                semaphores[i].acquire();
            }
        }
        for (int i = 0; i < len; i++) {
            Semaphore lastSemphore = i == 0 ? semaphores[len - 1] : semaphores[i - 1];
            Semaphore cur = semaphores[i];
            threads[i] = new orderThread(lastSemphore, cur, "线程" + i);
            threads[i].start();
        }
    }


    class orderThread extends Thread {

        /**
         * 每一个线程都保存上一个线程对应的信号量
         */
        Semaphore last;

        /**
         * 保存当前线程的信号量
         */
        Semaphore cur;

        orderThread(Semaphore last, Semaphore cur, String threadName) {
            super(threadName);
            this.last = last;
            this.cur = cur;
        }

        /**
         * 争夺上个线程的信号量,同时释放当前线程的信号量。这样唤醒下一个线程去争夺当前线程的信号量。
         */
        @Override
        public void run() {
            while (count <= 100) {
                try {
                    last.acquire();
                    //需要判断,防止线程被唤醒的时候,此时已经超过了100
                    if (count <= 100) {
                        System.out.println(Thread.currentThread().getName() + " : " + count++);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    cur.release();
                }
            }
        }
    }

    @Test
    public void test() throws Exception {
        print(3);
        Thread.sleep(3000);
    }

synchornized锁住的是什么

synchronized(obj) ,obj非static,锁的是实例对象,不是代码。当synchronized锁住一个对象后,别的线程如果也想拿到这个对象的锁,就必须等待这个线程执行完成释放锁,才能再次给对象加锁,这样才达到线程同步的目的。

synchronized(xx.class)锁的是class对象,全局性的,相当于锁住了代码块。

https://blog.csdn.net/xiao__gui/article/details/8188833

阻塞队列实现生产者消费者模型

    //生产者
    public static class Producer implements Runnable {
        private final BlockingQueue<Integer> blockingQueue;
        private volatile boolean flag;
        private Random random;

        public Producer(BlockingQueue<Integer> blockingQueue) {
            this.blockingQueue = blockingQueue;
            flag = false;
            random = new Random();
        }

        public void run() {
            while (!flag) {
                int info = random.nextInt(100);
                try {
                    blockingQueue.put(info);
                    System.out.println(Thread.currentThread().getName() + " produce " + info);
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        public void shutDown() {
            flag = true;
        }
    }

    //消费者
    public static class Consumer implements Runnable {
        private final BlockingQueue<Integer> blockingQueue;
        private volatile boolean flag;

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

        public void run() {
            while (!flag) {
                int info;
                try {
                    info = blockingQueue.take();
                    System.out.println(Thread.currentThread().getName() + " consumer " + info);
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }

        public void shutDown() {
            flag = true;
        }
    }

    public static void main(String[] args) {
        BlockingQueue<Integer> blockingQueue = new LinkedBlockingQueue<Integer>(10);
        Producer producer = new Producer(blockingQueue);
        Consumer consumer = new Consumer(blockingQueue);
        //创建5个生产者,5个消费者
        for (int i = 0; i < 10; i++) {
            if (i < 5) {
                new Thread(producer, "producer" + i).start();
            } else {
                new Thread(consumer, "consumer" + (i - 5)).start();
            }
        }

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        producer.shutDown();
        consumer.shutDown();

    }

手写生产者消费者模型

    Integer count = 0;
    Object obj = new Object();

    private void produce() {
        while (true) {
            synchronized (obj) {
                while (count == 10) {
                    try {
                        obj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                count++;
                System.out.println("生产后count = " + count);
                obj.notifyAll();
            }
        }
    }

    private void consume() {
        while (true) {
            synchronized (obj) {
                while (count <= 0) {
                    try {
                        obj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                count--;
                System.out.println("消费后count = " + count);
                obj.notifyAll();
            }
        }
    }

    @Test
    public void test() throws InterruptedException {
        Thread t1 = new Thread(()->produce());
        Thread t2 = new Thread(()->consume());
        t1.start();
        t2.start();
        t1.join();
        t2.join();
    }

Last updated

Was this helpful?