多线程编程面试常见题目(三)

LRU 缓存实现

在这里插入图片描述

/ 定义LRUCachepublic class LRUCache {

    // 内部静态类Node,代表双向链表中的节点
    private static class Node {
        int key, value;  // 节点的键和值
        Node prev, next; // 指向前一个和后一个节点的指针

        // 构造函数初始化节点的键和值
        Node(int k, int v) {
            key = k;
            value = v;
        }
    }

    // 缓存的最大容量
    private final int capacity;

    // 双向链表的虚拟头尾节点,形成循环链表
    private final Node dummy = new Node(0, 0);

    // 用于快速查找节点的键值映射
    private final Map<Integer, Node> keyToNode = new HashMap<>();

    // 构造函数,初始化LRUCache实例
    public LRUCache(int capacity) {
        this.capacity = capacity;

        // 初始化双向链表,头尾节点指向自身
        dummy.prev = dummy;
        dummy.next = dummy;
    }

    // 获取操作,返回指定键的值或-1(未找到)
    public int get(int key) {
        Node node = getNode(key); // 尝试获取节点
        return node != null ? node.value : -1; // 如果找到,返回值;否则返回-1
    }

    // 插入/更新操作,设置指定键的值
    public void put(int key, int value) {
        Node node = getNode(key); // 尝试获取节点

        // 如果节点存在,则更新其值,并将其移动到链表头部
        if (node != null) {
            node.value = value;
            return;
        }

        // 创建新节点
        node = new Node(key, value);

        // 将新节点添加到哈希表
        keyToNode.put(key, node);

        // 将新节点插入链表头部
        pushFront(node);

        // 如果超过最大容量,移除链表尾部的节点
        if (keyToNode.size() > capacity) {
            Node backNode = dummy.prev; // 获取链表尾部节点
            keyToNode.remove(backNode.key); // 移除哈希表中的对应项
            remove(backNode); // 从链表中移除节点
        }
    }

    // 私有方法,用于获取节点并将其移动到链表头部
    private Node getNode(int key) {
        // 如果键不在哈希表中,直接返回null
        if (!keyToNode.containsKey(key)) {
            return null;
        }

        Node node = keyToNode.get(key); // 从哈希表中获取节点

        // 移除节点
        remove(node);

        // 将节点插入链表头部
        pushFront(node);

        // 返回节点
        return node;
    }

    // 私有方法,用于从链表中移除指定节点
    private void remove(Node x) {
        // 更新前驱和后继节点的指针,移除节点
        x.prev.next = x.next;
        x.next.prev = x.prev;
    }

    // 私有方法,用于将节点插入到链表头部
    private void pushFront(Node x) {
        // 设置新节点的前后指针
        x.prev = dummy;
        x.next = dummy.next;

        // 更新链表头部节点的前后指针
        x.prev.next = x;
        x.next.prev = x;
    }
}

用 Java 实现栈

public class StackImpl {
    private int capacity;       // 栈的最大容量
    private int[] stack;        // 用于存储栈元素的数组
    private int top;            // 栈顶指针,初始值为 -1,表示空栈

    // 构造函数,初始化栈的大小和栈顶指针
    public StackImpl(int maxSize) {
        capacity = maxSize;
        stack = new int[capacity];
        top = -1;
    }

    // 弹出栈顶元素,若栈为空抛出异常
    public int pop() {
        if (top == -1) {
            throw new EmptyStackException();
        }
        int key = stack[top];
        top--;
        return key;
    }

    // 入栈操作,若栈满抛出异常
    public void push(int k) {
        if (top < capacity - 1) {
            top++;
            stack[top] = k;
        } else {
            throw new IllegalStateException("Stack is full");
        }
    }

    // 查看栈顶元素,若栈为空抛出异常
    public int peek() {
        if (top == -1) {
            throw new EmptyStackException();
        }
        return stack[top];
    }

    // 判断栈是否为空
    public boolean isEmpty() {
        return top == -1;
    }

    // 主方法,用于测试栈的功能
    public static void main(String[] args) {
        StackImpl stack1 = new StackImpl(10);   // 创建一个容量为10的栈
        stack1.push(1);
        stack1.push(2);

        stack1.pop();                           // 弹出栈顶元素,现在栈顶元素为1

        if (!stack1.isEmpty()) {                // 检查栈是否为空
            System.out.println(stack1.peek());  // 安全地调用peek方法,输出栈顶元素1
        } else {
            System.out.println("Stack is empty.");
        }
    }
}

加权轮询算法的实现

加权轮询算法(Weighted Round Robin,WRR)是一种调度算法,常用于负载均衡、任务调度等场景。在WRR中,每个实体都有一个权重,调度时按照权重分配调用的频率或时间间隔。下面是一个简单的加权轮询算法的Java实现,我们假设要调度的对象是一个列表,列表中的每个对象都有一个权重。

public class Scheduler {
    private List<WeightObject> weightObjects;
    private Queue<WeightObject> queue;
    private int currentWeight;
    public Scheduler(List<WeightObject> weightObjects)
    {
        this.weightObjects=weightObjects;
        this.queue=new LinkedList<WeightObject>();
        this.currentWeight=0;
        initScheduler();
    }
    public void initScheduler()
    {
        for(WeightObject obj:weightObjects)
        {
            for(int i=0;i<obj.getWeights();i++)
            {
                queue.add(obj);
            }
        }
    }

    public synchronized WeightObject getNext()
    {
        if(queue.isEmpty())
        {
            initScheduler();
        }

            WeightObject weightObject=queue.poll();
            currentWeight+=weightObject.getWeights();
            return weightObject;
    }

    public int getCurrentWeight() {
        return currentWeight;
    }

    public static <WeightedObject> void main(String[] args) {
        List<WeightObject> objects = new LinkedList<>();
        objects.add(new WeightObject("A", 2));
        objects.add(new WeightObject("B", 1));
        objects.add(new WeightObject("C", 3));

        Scheduler scheduler = new Scheduler(objects);
        for (int i = 0; i < 100; i++) {
            WeightObject obj = scheduler.getNext();
            System.out.println("Selected: " + obj.getName());
        }
    }
}
class WeightObject
{
    private String name;
    private int weights;

    public WeightObject(String name, int weights) {
        this.name = name;
        this.weights = weights;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getWeights() {
        return weights;
    }

    public void setWeights(int weights) {
        this.weights = weights;
    }
}

死锁现象

public class DeadLock {
    private final Lock lock1 = new ReentrantLock();
    private final Lock lock2 = new ReentrantLock();

    public void printA()
    {
        lock1.lock();
        System.out.println(Thread.currentThread().getName()+"线程A获取锁1");
        try
        {
            Thread.sleep(10);
            System.out.println(Thread.currentThread().getName()+"线程A尝试获取锁2");
            lock2.lock();
            System.out.println(Thread.currentThread().getName()+"线程A得到锁2");

        }
        catch (Exception e)
        {
            Thread.interrupted();
        }
        finally {
            lock2.unlock();
            lock1.unlock();
        }
    }
    public void printB()
    {
        lock2.lock();
        System.out.println(Thread.currentThread().getName()+"线程B获取锁2");
        try
        {
            Thread.sleep(10);
            System.out.println(Thread.currentThread().getName()+"线程B尝试获取锁1");
            lock1.lock();
            System.out.println(Thread.currentThread().getName()+"线程B得到锁1");

        }
        catch (Exception e)
        {
            Thread.interrupted();
        }
        finally {
            lock1.unlock();
            lock2.unlock();
        }
    }

    public static void main(String[] args) {
        DeadLock deadLock =new DeadLock();
        Thread thread1=new Thread(deadLock::printA, "a");
        Thread thread2=new Thread(deadLock::printB, "B");
        thread1.start();
        thread2.start();
        try
        {
            thread1.join();
            thread2.join();
        }catch (Exception e)
        {
            Thread.interrupted();
        }
    }

}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值