欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java面经查缺补漏之三十六天(前天面试完美团,不知道是否凉凉,今天主要学生产者消费者模型)

程序员文章站 2022-05-12 16:34:51
...

1.手写一个生产者消费者模型?

参考:https://blog.csdn.net/u010983881/article/details/78554671?depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-4&utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-4

查了一下,这篇讲的是最好的!一共有三种方式,阻塞队列,synchronized的,lock的

最简单的一个,基于阻塞队列的:

import java.util.Random;
import java.util.concurrent.LinkedBlockingQueue;

public class producerByBq {
    private static final int CAPACITY = 5;
    public static void main(String[] args)
    {
        LinkedBlockingQueue<Integer> blockingQueue = new LinkedBlockingQueue<Integer>(CAPACITY);
        Thread producer1 = new producer("P-1", blockingQueue);
        Thread producer2 = new producer("P-2", blockingQueue);
        Thread consumer1 = new consumer("C1", blockingQueue);
        Thread consumer2 = new consumer("C2", blockingQueue);
        Thread consumer3 = new consumer("C3", blockingQueue);
        producer1.start();
        producer2.start();
        consumer1.start();
        consumer2.start();
        consumer3.start();
    }
    public static class producer extends Thread
    {
        private LinkedBlockingQueue<Integer> blockingQueue;
        private String name;
        private int i=0;
        public producer(String name,LinkedBlockingQueue<Integer> blockingQueue)
        {
            //这个supername是干什么的
            super(name);
            this.blockingQueue=blockingQueue;
            this.name=name;
        }
        public void run()
        {
            while(true)
            {
                try {
                    blockingQueue.put(i);
                    System.out.println("[" + name + "] Producing value : +" + i);
                    i++;
                    Thread.sleep(new Random().nextInt(1000));
                }catch (Exception e)
                {
                    e.printStackTrace();
                }
            }
        }

    }
    public static class consumer extends Thread
    {
        private LinkedBlockingQueue<Integer> blockingQueue;
        private String name;
        public consumer(String name,LinkedBlockingQueue<Integer> blockingQueue)
        {
            super(name);
            this.blockingQueue=blockingQueue;
            this.name=name;
        }
        public void run()
        {
            while(true)
            {
                try {
                    int x=blockingQueue.take();
                    System.out.println("[" + name + "] Consuming : " + x);
                    Thread.sleep(new Random().nextInt(1000));
                }catch (Exception e)
                {
                    e.printStackTrace();
                }
            }
        }
    }
}

第二个,基于synchronized的

import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;

public class producerBySyn {
    private static final int CAPACITY = 5;
    public static void main(String[] args)
    {
        Queue<Integer> queue = new LinkedList<Integer>();
        Thread producer1 = new producer("P-1", queue,CAPACITY);
        Thread producer2 = new producer("P-2", queue,CAPACITY);
        Thread consumer1 = new consumer("C1", queue);
        Thread consumer2 = new consumer("C2", queue);
        Thread consumer3 = new consumer("C3", queue);
        producer1.start();
        producer2.start();
        consumer1.start();
        consumer2.start();
        consumer3.start();
    }
    public static class producer extends Thread
    {
        private final Queue<Integer> queue;
        private String name;
        private int maxSize;
        private int i=0;
        public producer(String name,Queue<Integer> queue,int maxSize)
        {
            super(name);
            this.queue=queue;
            this.name=name;
            this.maxSize=maxSize;
        }
        public void run()
        {
            while(true)
            {
                synchronized (queue)
                {
                    while(queue.size()==maxSize)
                    {
                        try {
                            System.out .println("Queue is full, Producer[" + name + "] thread waiting for " + "consumer to take something from queue.");
                            queue.wait();
                        }catch (Exception e)
                        {
                            e.printStackTrace();
                        }
                    }
                    System.out.println("[" + name + "] Producing value : +" + i);
                    queue.offer(i++);
                    queue.notifyAll();
                    try {
                        Thread.sleep(new Random().nextInt(1000));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

    }
    public static class consumer extends Thread
    {
        private final Queue<Integer> queue;
        private String name;
        public consumer(String name,Queue<Integer> queue)
        {
            super(name);
            this.queue=queue;
            this.name=name;
        }
        public void run()
        {
            while(true)
            {
                synchronized (queue)
                {
                    while(queue.size()==0)
                    {
                        try {
                            System.out.println("Queue is empty, Consumer[" + name + "] thread is waiting for Producer");
                            queue.wait();
                        }catch (Exception e)
                        {
                            e.printStackTrace();
                        }
                    }
                    int x = queue.poll();
                    System.out.println("[" + name + "] Consuming value : " + x);
                    queue.notifyAll();
                    try {
                        Thread.sleep(new Random().nextInt(1000));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

 第三个,基于Lock和condition的

import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class producerByLock {
    private static final int CAPACITY = 5;
    private static final Lock lock = new ReentrantLock();
    private static final Condition fullCondition = lock.newCondition();     //队列满的条件
    private static final Condition emptyCondition = lock.newCondition();        //队列空的条件
    public static void main(String[] args)
    {
        Queue<Integer> queue = new LinkedList<Integer>();
        Thread producer1 = new producer("P-1", queue,CAPACITY);
        Thread producer2 = new producer("P-2", queue,CAPACITY);
        Thread consumer1 = new consumer("C1", queue);
        Thread consumer2 = new consumer("C2", queue);
        Thread consumer3 = new consumer("C3", queue);
        producer1.start();
        producer2.start();
        consumer1.start();
        consumer2.start();
        consumer3.start();
    }
    public static class producer extends Thread
    {
        private final Queue<Integer> queue;
        private String name;
        private int maxSize;
        private int i=0;
        public producer(String name,Queue<Integer> queue,int maxSize)
        {
            super(name);
            this.queue=queue;
            this.name=name;
            this.maxSize=maxSize;
        }
        public void run()
        {
            while(true)
            {
                lock.lock();
                while(queue.size() == maxSize){
                    try {
                        System.out .println("Queue is full, Producer[" + name + "] thread waiting for " + "consumer to take something from queue.");
                        //条件不满足,生产阻塞
                        fullCondition.await();
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                }
                System.out.println("[" + name + "] Producing value : +" + i);
                queue.offer(i++);

                //唤醒其他所有生产者、消费者
                fullCondition.signalAll();
                emptyCondition.signalAll();

                //释放锁
                lock.unlock();

                try {
                    Thread.sleep(new Random().nextInt(1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

    }
    public static class consumer extends Thread
    {
        private final Queue<Integer> queue;
        private String name;
        public consumer(String name,Queue<Integer> queue)
        {
            super(name);
            this.queue=queue;
            this.name=name;
        }
        public void run()
        {
            while(true)
            {
                lock.lock();

                while(queue.isEmpty()){
                    try {
                        System.out.println("Queue is empty, Consumer[" + name + "] thread is waiting for Producer");
                        //条件不满足,消费阻塞
                        emptyCondition.await();
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
                int x = queue.poll();
                System.out.println("[" + name + "] Consuming value : " + x);

                //唤醒其他所有生产者、消费者
                fullCondition.signalAll();
                emptyCondition.signalAll();

                //释放锁
                lock.unlock();

                try {
                    Thread.sleep(new Random().nextInt(1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

2.Java多线程notify/notifyAll唤醒的是谁?

参考:https://blog.csdn.net/q5706503/article/details/84591159

3.什么是时间片轮转?

时间片轮转说的是操作系统的一种调度算法,用于交互式系统,每一个进程都给分配一个时间片,然后进行快速的切换,但是速度很快,人看不到这些切换。另外还有优先级调度算法,多级反馈队列算法(既有优先级又有时间片)

4.什么是分布式事务?

参考:https://blog.csdn.net/bjweimengshu/article/details/79607522

分布式事务用于在分布式系统中保证不同节点之间的数据一致性。

XA两阶段提交:

(1)在XA分布式事务的第一阶段,作为事务协调者的节点会首先向所有的参与者节点发送Prepare请求。在接到Prepare请求之后,每一个参与者节点会各自执行与事务有关的数据更新,写入Undo Log和Redo Log。如果参与者执行成功,暂时不提交事务,而是向事务协调节点返回“完成”消息。当事务协调者接到了所有参与者的返回消息,整个分布式事务将会进入第二阶段。

(2)作为事务协调者的节点给所有事务参与者发出Commit请求。接到Commit请求之后,事务参与者节点会各自进行本地的事务提交,并释放锁资源。当本地事务完成提交后,将会向事务协调者返回“完成”消息。当事务协调者接收到所有事务参与者的“完成”反馈,整个分布式事务完成。

在XA的第一阶段,如果某个事务参与者反馈失败消息,说明该节点的本地事务执行不成功,必须回滚。

于是在第二阶段,事务协调节点向所有的事务参与者发送Abort请求。接收到Abort请求之后,各个事务参与者节点需要在本地进行事务的回滚操作,回滚操作依照Undo Log来进行。

5.常见的负载均衡算法?

(1)轮询
将所有请求,依次分发到每台服务器上,适合服务器硬件相同的场景。
优点:服务器请求数目相同;

缺点:服务器压力不一样,不适合服务器配置不同的情况;

(2)随机
请求随机分配到各台服务器上。
优点:使用简单;

缺点:不适合机器配置不同的场景

(3)最少链接
将请求分配到连接数最少的服务器上(目前处理请求最少的服务器)。
优点:根据服务器当前的请求处理情况,动态分配;

缺点:算法实现相对复杂,需要监控服务器请求连接数;

(4)Hash(源地址散列)
根据IP地址进行Hash计算,得到IP地址。
优点:将来自同一IP地址的请求,同一会话期内,转发到相同的服务器;实现会话粘滞。

缺点:目标服务器宕机后,会话会丢失;

(5)加权
在轮询,随机,最少链接,Hash等算法的基础上,通过加权的方式,进行负载服务器分配。

优点:根据权重,调节转发服务器的请求数目;

缺点:使用相对复杂;