Java非算法手撕实现

还没写完,慢慢更

1.多线程交替打印:打印内容为ABC循环或者交替打印一段话

import java.util.concurrent.Semaphore;

public class ThreadExample {
    public static Semaphore semaphore1 = new Semaphore(1);
    public static Semaphore semaphore2 = new Semaphore(0);
    public static Semaphore semaphore3 = new Semaphore(0);

    public static void main(String[] args) {
        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        semaphore1.acquire();
                        System.out.println("A");
                        semaphore2.release();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        });
        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        semaphore2.acquire();
                        System.out.println("B");
                        semaphore3.release();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        });
        Thread threadC = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        semaphore3.acquire();
                        System.out.println("C");
                        semaphore1.release();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        });
        threadA.start();
        threadB.start();
        threadC.start();
    }
}

    2. 多线程场景题:有5个人,在那赛跑,请你设计一个多线程的裁判程序给出他们赛跑的结果顺序,5个人的速度随机处理


package org.example.countdownlatch;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;

/**
 * 5个线程模拟赛马,所有马就绪后才能开跑,所有马到达终点后裁判宣布赛马成绩
 * CountDownLatch和CyclicBarrier
 */
public class HorseRace {
    // 用于存储赛马成绩
    private static List<String> results = Collections.synchronizedList(new ArrayList<>());

    // 用于控制所有马同时开跑
    private static CountDownLatch startLatch = new CountDownLatch(1);

    // 用于确保所有马到达终点后再宣布成绩
    private static CyclicBarrier finishBarrier = new CyclicBarrier(5, new Runnable() {
        @Override
        public void run() {
            // 裁判宣布成绩
            System.out.println("Race finished! Announcing results:");
            for (String result : results) {
                System.out.println(result);
            }
        }
    });

    public static void main(String[] args) {
        for (int i = 1; i <= 5; i++) {
            new Thread(new Horse("Horse " + i)).start();
        }

        // 所有马就绪后开跑
        try {
            System.out.println("All horses ready. Race starts now!");
            startLatch.countDown(); // 马开跑
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    static class Horse implements Runnable {
        private String name;

        public Horse(String name) {
            this.name = name;
        }

        @Override
        public void run() {
            try {
                // 马就绪,等待开跑信号
                startLatch.await();

                // 马开始跑
                long raceTime = (long) (Math.random() * 10000); // 模拟跑的时间
                Thread.sleep(raceTime);

                // 马到达终点
                results.add(name + " finished in " + raceTime + " ms");

                // 等待其他马到达终点
                finishBarrier.await();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

    3. 手写线程池(实现一个简易线程池)

    实现简易线程池,首先定义接口,主要包括,线程池基本功能,拒绝策略,线程池工厂,等待的任务队列。以及自定义异常,然后实现线程池的基本功能。

    线程池基本功能接口


public interface ThreadPool {
    //提交任务到线程池
    void execute(Runnable runnable);

    //关闭
    void shutdown();

    //获取线程池初始化时的线程大小
    int getInitSize();

    //获取线程池最大线程数
    int getMaxSize();

    //获取线程池核心线程数量
    int getCoreSize();

    //获取活跃线程数量
    int getActiveCount();

    //获取线程池缓存队列大小
    int getQueueSize();

    //查看线程是否被销毁
    boolean isShutdown();

}

拒绝策略接口

@FunctionalInterface
//这个类定义了当缓存队列达到上限的时候,将通过什么方式来通知提交者,实现了默认的三种方法
public interface DenyPolicy {
    void reject(Runnable runnable, ThreadPool threadPool);
}

线程池工厂接口

@FunctionalInterface
//创建线程的工厂
public interface ThreadFactory {

    Thread creatThread(Runnable runnable);
}

任务队列接口

//缓存提交到线程池的队列任务
public interface RunnableQueue {
    //新线程进来时,提交任务到缓存队列
    void offer(Runnable runnable);

    //取出线程
    Runnable take();

    //获取队列中线程的数量
    int size();
}

自定义异常

//自定义异常
public class RunnableDenyException extends RuntimeException {
    public RunnableDenyException(String msg) {
        super(msg);
    }
}

拒绝策略实现。(三个拒绝策略)

    //直接丢弃线程,什么都不做,不通知
    class DiscardDenyPolicy implements DenyPolicy {

        @Override
        public void reject(Runnable runnable, ThreadPool threadPool) {

        }
    }

    //抛出异常通知
    class AbortDenyPolicy implements DenyPolicy {

        @Override
        public void reject(Runnable runnable, ThreadPool threadPool) {
            throw new RunnableDenyException("这个线程:" + runnable + " 将会被丢弃");
        }
    }

    //使线程在提交者所在的线程中运行
    class RunnerDenyPolicy implements DenyPolicy {
        @Override
        public void reject(Runnable runnable, ThreadPool threadPool) {
            if (!threadPool.isShutdown()) {
                runnable.run();
            }
        }
    }

任务队列实现


import java.util.LinkedList;

public class LinkedRunnableQueue implements RunnableQueue {
    //任务队列的最大容量
    private final int limit;
    //容量最大时,需要使用的拒绝策略
    private final DenyPolicy denyPolicy;
    //存放任务的队列
    private final LinkedList<Runnable> runnableLinkedList;
    private final ThreadPool threadPool;

    public LinkedRunnableQueue(int limit, DenyPolicy denyPolicy, ThreadPool threadPool) {
        this.limit = limit;
        this.denyPolicy = denyPolicy;
        this.threadPool = threadPool;
        runnableLinkedList = new LinkedList<>();
    }

    @Override
    public void offer(Runnable runnable) {
        synchronized (runnableLinkedList) {
            //如果缓存数量超过最大值,则使用拒绝策略
            if (runnableLinkedList.size() >= limit) {
                denyPolicy.reject(runnable, threadPool);
            } else {
                //成功加入list的末尾,并唤醒阻塞中的线程
                runnableLinkedList.addLast(runnable);
                runnableLinkedList.notifyAll();
            }
        }
    }

    @Override
    public Runnable take() {
        synchronized (runnableLinkedList) {
            //如果缓存队列为空,则挂起,等待新的任务进来唤醒
            while (runnableLinkedList.isEmpty()) {
                try {
                    runnableLinkedList.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        return runnableLinkedList.removeFirst();
    }

    @Override
    public int size() {
        synchronized (runnableLinkedList) {
            //返回list中的个数
            return runnableLinkedList.size();
        }
    }
}

线程工厂实现

import java.util.concurrent.atomic.AtomicInteger;

class DefaultThreadFactory implements ThreadFactory {
    private static final AtomicInteger GROUP_COUNTER = new AtomicInteger(1);
    private static final ThreadGroup group = new ThreadGroup("我的线程-" +
            GROUP_COUNTER.getAndDecrement());
    private static final AtomicInteger COUNTER = new AtomicInteger(0);

    @Override
    public Thread creatThread(Runnable runnable) {
        return new Thread(group, runnable, "线程池-" + COUNTER.getAndDecrement());
    }
}

线程池实现


import java.util.ArrayDeque;
import java.util.Queue;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

public class BasicThreadPool extends Thread implements ThreadPool {
    //初始化线程池的数量
    private final int initSize;
    //线程池最大线程数
    private final int maxSize;
    //线程池核心线程数
    private final int coreSize;
    //当前活跃线程的数量
    private int activeCount;
    //创建线程的工厂
    private final ThreadFactory threadFactory;
    //任务队列
    private final RunnableQueue runnableQueue;
    //线程是否被摧毁
    private volatile boolean isShutdown = false;
    //工作队列
    private final Queue<ThreadTask> internalTasks = new ArrayDeque<>();
    //拒绝策略
    private final static DenyPolicy DEFAULT_DENY_POLICY = new DiscardDenyPolicy();
    //看下面,自定义线程工厂
    private final static ThreadFactory DEFAULT_THREAD_FACTORY =
            new DefaultThreadFactory();
    private final long keepAliveTime;
    private final TimeUnit timeUnit;


    //构造默认线程池时需要传入的参数:初始线程池的数量,最大线程的数量,核心线程数量,任务队列的最大数
    public BasicThreadPool(int initSize, int maxSize, int coreSize,
                           int queueSize) {
        this(initSize, maxSize, coreSize, DEFAULT_THREAD_FACTORY,
                queueSize, DEFAULT_DENY_POLICY, 2,
                TimeUnit.SECONDS);
    }

    public BasicThreadPool(int initSize, int maxSize, int coreSize, ThreadFactory threadFactory, int queueSize,
                           DenyPolicy denyPolicy, long keepAliveTime, TimeUnit timeUnit) {
        this.initSize = initSize;
        this.maxSize = maxSize;
        this.coreSize = coreSize;
        this.threadFactory = threadFactory;
        this.runnableQueue = new LinkedRunnableQueue(queueSize, denyPolicy, this);
        this.keepAliveTime = keepAliveTime;
        this.timeUnit = timeUnit;
        this.init();
    }

    //初始化线程池并创建initSize个线程
    private void init() {
        //继承了Thread类,初始化时先启动自己
        start();
        IntStream.range(0, initSize).forEach(i -> newThread());
    }

    //创建新的任务线程并启动
    private void newThread() {
        InternalTask internalTask = new InternalTask(runnableQueue);
        Thread thread = this.threadFactory.creatThread(internalTask);
        ThreadTask threadTask = new ThreadTask(thread, internalTask);
        internalTasks.offer(threadTask);
        this.activeCount++;
        thread.start();
    }

    private void removeThread() {
        ThreadTask threadTask = internalTasks.remove();
        threadTask.internalTask.stop();
        this.activeCount--;
    }

    @Override
    public void execute(Runnable runnable) {
        if (this.isShutdown) {
            throw new IllegalStateException("这个线程池已经被销毁了");
        }
        this.runnableQueue.offer(runnable);
    }

    @Override
    public void run() {
        //自动维护线程池
        while (!isShutdown && !isInterrupted()) {
            try {
                timeUnit.sleep(keepAliveTime);
            } catch (InterruptedException e) {
                e.printStackTrace();
                isShutdown = true;
                break;
            }
            synchronized (this) {
                if (isShutdown) {
                    break;
                }
                //当任务队列大于0,活跃线程小于核心线程的时候,扩容线程
                if (runnableQueue.size() > 0 && activeCount < coreSize) {
                    IntStream.range(initSize, coreSize).forEach(i -> newThread());
                    continue;
                }
                if (runnableQueue.size() > 0 && activeCount < maxSize) {
                    IntStream.range(coreSize, maxSize).forEach(i -> newThread());
                }
                if (runnableQueue.size() == 0 && activeCount > coreSize) {
                    IntStream.range(coreSize, activeCount).forEach(i -> removeThread());
                }

            }
        }
    }

    @Override
    public void shutdown() {

    }

    //这一段方法不是特别重要,就有读者自己写
    @Override
    public int getInitSize() {
        return 0;
    }

    @Override
    public int getMaxSize() {
        return 0;
    }

    @Override
    public int getCoreSize() {
        return 0;
    }

    @Override
    public int getActiveCount() {
        return 0;
    }

    @Override
    public int getQueueSize() {
        return 0;
    }

    @Override
    public boolean isShutdown() {
        return this.isShutdown;
    }

    //把线程和internalTask一个组合
    private static class ThreadTask {
        public ThreadTask(Thread thread, InternalTask internalTask) {
            this.thread = thread;
            this.internalTask = internalTask;
        }

        Thread thread;
        InternalTask internalTask;
    }


}

线程池内部使用


//实现Runnable,用于线程池内部,该类会用到RunnableQueue,会不断的从队列中拿出线程并运行
public class InternalTask implements Runnable {

    private final RunnableQueue runnableQueue;
    private volatile boolean running = true;

    public InternalTask(RunnableQueue runnableQueue) {
        this.runnableQueue = runnableQueue;
    }

    @Override
    public void run() {
        //如果当前线程在运行中切没有被中断,则不断从缓存队列中拿出线程运行
        while (running && !Thread.currentThread().isInterrupted()) {
            try {
                Runnable task = runnableQueue.take();
                task.run();
            } catch (Exception e) {
                running = false;
                break;
            }
        }
    }

    //停止当前任务,会在shutdown中使用
    public void stop() {
        this.running = false;
    }
}

测试类

import java.util.concurrent.TimeUnit;

public class Main {
    public static void main(String[] args) {
        final ThreadPool threadPool = new BasicThreadPool(2, 6, 4, 100);
        for (int i = 0; i <= 20; i++) {
            threadPool.execute(() -> {
                try {
                    TimeUnit.SECONDS.sleep(1);
                    System.out.println(Thread.currentThread().getName() + "开始了");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
    }
}

4. 生产者-消费者模型:例如一个厨子4s生产一个,一个客人10s消费一个


import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class NonBlockingProducerConsumer {
    // 定义一个非阻塞队列作为共享缓冲区
    private static final Queue<String> queue = new ConcurrentLinkedQueue<>();
    private static final int MAX_CAPACITY = 5; // 队列的最大容量

    // 定义锁和条件变量
    private static final Lock lock = new ReentrantLock();
    private static final Condition notFull = lock.newCondition(); // 队列未满
    private static final Condition notEmpty = lock.newCondition(); // 队列非空

    public static void main(String[] args) {
        // 创建厨子线程(生产者)
        Thread chefThread = new Thread(() -> {
            try {
                while (true) {
                    lock.lock(); // 获取锁
                    try {
                        // 如果队列已满,等待
                        while (queue.size() == MAX_CAPACITY) {
                            System.out.println("Queue is full, Chef is waiting...");
                            notFull.await();
                        }

                        // 生产菜品
                        String dish = "Dish-" + System.currentTimeMillis();
                        queue.add(dish);
                        System.out.println("Chef produced: " + dish);

                        // 唤醒消费者
                        notEmpty.signalAll();
                    } finally {
                        lock.unlock(); // 释放锁
                    }

                    // 模拟厨子生产时间
                    Thread.sleep(4000);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        // 创建客人线程(消费者)
        Thread customerThread = new Thread(() -> {
            try {
                while (true) {
                    lock.lock(); // 获取锁
                    try {
                        // 如果队列为空,等待
                        while (queue.isEmpty()) {
                            System.out.println("Queue is empty, Customer is waiting...");
                            notEmpty.await();
                        }

                        // 消费菜品
                        String dish = queue.poll();
                        System.out.println("Customer consumed: " + dish);

                        // 唤醒生产者
                        notFull.signalAll();
                    } finally {
                        lock.unlock(); // 释放锁
                    }

                    // 模拟客人消费时间
                    Thread.sleep(10000);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        // 启动线程
        chefThread.start();
        customerThread.start();
    }
}

    5. 单例模式:懒汉,饿汉,双重校验锁

    懒汉

public class Singleton {
    //私有构造方法
    private Singleton() {}

    //在成员位置创建该类的对象
    private static Singleton instance;

    //对外提供静态方法获取该对象
    public static Singleton getInstance() {

        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

恶汉

public class Singleton {
    //私有构造方法
    private Singleton() {}

    //在成员位置创建该类的对象
    private static Singleton instance = new Singleton();

    //对外提供静态方法获取该对象
    public static Singleton getInstance() {
        return instance;
    }
}

双重校验锁

public class Singleton {

    //私有构造方法
    private Singleton() {}

    private static volatile Singleton instance;

   //对外提供静态方法获取该对象
    public static Singleton getInstance() {
        //第一次判断,如果instance不为null,不进入抢锁阶段,直接返回实际
        if(instance == null) {
            synchronized (Singleton.class) {
                //抢到锁之后再次判断是否为空
                if(instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

    6. 动态代理

    jdk动态代理

//卖票接口
public interface SellTickets {
    void sell();
}

//火车站  火车站具有卖票功能,所以需要实现SellTickets接口
public class TrainStation implements SellTickets {

    public void sell() {
        System.out.println("火车站卖票");
    }
}

//代理工厂,用来创建代理对象
public class ProxyFactory {

    private TrainStation station = new TrainStation();

    public SellTickets getProxyObject() {
        //使用Proxy获取代理对象
        /*
            newProxyInstance()方法参数说明:
                ClassLoader loader : 类加载器,用于加载代理类,使用真实对象的类加载器即可
                Class<?>[] interfaces : 真实对象所实现的接口,代理模式真实对象和代理对象实现相同的接口
                InvocationHandler h : 代理对象的调用处理程序
         */
        SellTickets sellTickets = (SellTickets) Proxy.newProxyInstance(station.getClass().getClassLoader(),
                station.getClass().getInterfaces(),
                new InvocationHandler() {
                    /*
                        InvocationHandler中invoke方法参数说明:
                            proxy : 代理对象
                            method : 对应于在代理对象上调用的接口方法的 Method 实例
                            args : 代理对象调用接口方法时传递的实际参数
                     */
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                        System.out.println("代理点收取一些服务费用(JDK动态代理方式)");
                        //执行真实对象
                        Object result = method.invoke(station, args);
                        return result;
                    }
                });
        return sellTickets;
    }
}

//测试类
public class Client {
    public static void main(String[] args) {
        //获取代理对象
        ProxyFactory factory = new ProxyFactory();
        
        SellTickets proxyObject = factory.getProxyObject();
        proxyObject.sell();
    }
}

    7. 手写一个HashMap,HashSet

    HashMap

import java.util.LinkedList;

public class MyHashMap<K, V> {
    private static final int DEFAULT_CAPACITY = 16; // 默认容量
    private static final double LOAD_FACTOR = 0.75; // 负载因子

    private LinkedList<Node<K, V>>[] buckets;
    private int size; // 当前元素数量

    public MyHashMap() {
        this(DEFAULT_CAPACITY);
    }

    @SuppressWarnings("unchecked")
    public MyHashMap(int capacity) {
        buckets = new LinkedList[capacity];
        for (int i = 0; i < capacity; i++) {
            buckets[i] = new LinkedList<>();
        }
        size = 0;
    }

    // 存储键值对
    public void put(K key, V value) {
        int index = getIndex(key); // 计算哈希值对应的桶索引
        LinkedList<Node<K, V>> bucket = buckets[index];

        // 检查是否已经存在该键
        for (Node<K, V> node : bucket) {
            if (node.key.equals(key)) {
                node.value = value; // 更新值
                return;
            }
        }

        // 如果不存在该键,则新增节点
        bucket.add(new Node<>(key, value));
        size++;

        // 检查是否需要扩容
        if ((double) size / buckets.length > LOAD_FACTOR) {
            resize();
        }
    }

    // 获取值
    public V get(K key) {
        int index = getIndex(key);
        LinkedList<Node<K, V>> bucket = buckets[index];

        for (Node<K, V> node : bucket) {
            if (node.key.equals(key)) {
                return node.value;
            }
        }
        return null; // 如果没有找到键,返回 null
    }

    // 删除键值对
    public void remove(K key) {
        int index = getIndex(key);
        LinkedList<Node<K, V>> bucket = buckets[index];

        for (Node<K, V> node : bucket) {
            if (node.key.equals(key)) {
                bucket.remove(node);
                size--;
                return;
            }
        }
    }

    // 获取当前元素数量
    public int size() {
        return size;
    }

    // 扩容方法
    @SuppressWarnings("unchecked")
    private void resize() {
        LinkedList<Node<K, V>>[] oldBuckets = buckets;
        buckets = new LinkedList[oldBuckets.length * 2];
        for (int i = 0; i < buckets.length; i++) {
            buckets[i] = new LinkedList<>();
        }
        size = 0;

        // 将旧桶中的所有元素重新插入新桶
        for (LinkedList<Node<K, V>> bucket : oldBuckets) {
            for (Node<K, V> node : bucket) {
                put(node.key, node.value);
            }
        }
    }

    // 计算桶索引
    private int getIndex(K key) {
        return Math.abs(key.hashCode()) % buckets.length;
    }

    // 内部类:存储键值对的节点
    private static class Node<K, V> {
        K key;
        V value;

        Node(K key, V value) {
            this.key = key;
            this.value = value;
        }
    }
}

    HashSet(在HashMap基础上实现)

public class MyHashSet<E> {
    private static final Object PRESENT = new Object(); // 占位对象
    private final MyHashMap<E, Object> map;

    public MyHashSet() {
        map = new MyHashMap<>();
    }

    // 添加元素
    public boolean add(E e) {
        return map.put(e, PRESENT) == null; // 如果之前不存在该键,返回 true
    }

    // 删除元素
    public boolean remove(E e) {
        return map.get(e) != null && (map.remove(e) != null);
    }

    // 判断是否包含某个元素
    public boolean contains(E e) {
        return map.get(e) != null;
    }

    // 获取集合大小
    public int size() {
        return map.size();
    }

    // 清空集合
    public void clear() {
        map = new MyHashMap<>();
    }
}

    8. 有一个0-4的随机器rand4,如何实现0-6的随机器rand6,概率相同。拓展:rand X = func(rand Y),实现func函数

    rand4实现rand6

public class Rand6FromRand4 {
    // 假设 rand4 是一个已有的函数,返回 [0, 4] 的随机数
    public static int rand4() {
        return (int) (Math.random() * 5); // 模拟 rand4
    }

    // 实现 rand6,返回 [0, 6] 的随机数
    public static int rand6() {
        while (true) {
            // 调用两次 rand4,生成一个范围为 [0, 24] 的随机数
            int num = rand4() * 5 + rand4(); // num ∈ [0, 24]

            // 只使用前 21 个数(21 是 7 的倍数,可以均匀分配到 [0, 6])
            if (num < 21) {
                return num % 7; // 将 [0, 20] 映射到 [0, 6]
            }
            // 如果 num ≥ 21,丢弃并重新生成
        }
    }
}

randx实现randy

public class RandXFromRandY {
    // 假设 randY 是一个已有的函数,返回 [0, Y-1] 的随机数
    public static int randY(int Y) {
        return (int) (Math.random() * Y); // 模拟 randY
    }

    // 实现 randX,返回 [0, X-1] 的随机数
    public static int randX(int X, int Y) {
        int n = 1;
        int range = Y;

        // 找到最小的 n,使得 Y^n >= X
        while (range < X) {
            range *= Y;
            n++;
        }

        while (true) {
            // 调用 n 次 randY,生成一个范围为 [0, Y^n - 1] 的随机数
            int num = 0;
            int factor = 1;
            for (int i = 0; i < n; i++) {
                num += randY(Y) * factor;
                factor *= Y;
            }

            // 只使用前 k 个数,k 是 X 的倍数
            if (num < range / X * X) {
                return num % X; // 将 [0, k-1] 映射到 [0, X-1]
            }
            // 如果超出范围,丢弃并重新生成
        }
    }
}

    9. 及其逆天的一个阿里手撕,来自于@byebyeneu:写三个Spring接口,调用第一个接口的时候返回这个接口的累计调用次数,调用第二个接口的时候返回调用这个接口的累计p99,调用第三个接口的时候,如果这个接口这时的qps<10,返回success,如果这个接口这时qps>10,返回err

    10.判断今天星期几

import java.time.LocalDate;
import java.time.DayOfWeek;

public class DayOfWeekExample {
    public static void main(String[] args) {
        // 获取当前日期
        LocalDate today = LocalDate.now();

        // 获取今天是星期几
        DayOfWeek dayOfWeek = today.getDayOfWeek();

        // 输出星期几(英文)
        System.out.println("Today is: " + dayOfWeek);

        // 如果需要输出中文的星期几
        String[] chineseWeekdays = {"星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"};
        int dayValue = dayOfWeek.getValue(); // 1 表示星期一,7 表示星期日
        System.out.println("今天是: " + chineseWeekdays[dayValue - 1]);
    }
}

    11.求YYYY-MM-DD的上一天

public static String getPreviousDay(String dateStr) throws Exception {
        // 定义日期格式
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        // 将字符串解析为 Date 对象
        Date date = sdf.parse(dateStr);

        // 使用 Calendar 计算上一天
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH, -1);

        // 将结果格式化为字符串并返回
        return sdf.format(calendar.getTime());
    }

    12.两个线程和队列模拟TCP三次握手

全部评论
m
1 回复 分享
发布于 2024-12-29 14:12 河南
不是哥们,都26快手了,还在这写八股呢
1 回复 分享
发布于 2024-12-18 22:54 天津
收藏了佬
1 回复 分享
发布于 2024-12-11 18:49 山西
1 回复 分享
发布于 2024-12-11 15:12 山西
mark一下
点赞 回复 分享
发布于 05-16 20:57 江苏
mark
点赞 回复 分享
发布于 05-14 21:59 安徽
mark一下
点赞 回复 分享
发布于 04-22 09:06 湖北
mark
点赞 回复 分享
发布于 03-16 11:17 广东
第八个的代码: import java.util.HashMap; import java.util.Map; import java.util.Random; /** 有一个1-4的随机器rand4,如何实现1-6的随机器rand6,概率相同。拓展:rand X = func(rand Y),实现func函数* */ public class RandMain { static Map<integer> map = new HashMap<>(); public static void main(String[] args) { map.put(1, 0); map.put(2, 0); map.put(3, 0); map.put(4, 0); map.put(5, 0); map.put(6, 0); for (int i = 0; i < 10000000; i++) { int rand = rand6(); map.put(rand, map.get(rand) + 1); } for(Map.Entry<integer> entry : map.entrySet()){ System.out.println(entry.getKey() + ":" + entry.getValue()); } } private static int rand6() { int num = (rand4() - 1) * 4 + rand4(); while(num > 6){ num = (rand4() - 1) * 4 + rand4(); } return num; } private static int rand4() { return new Random().nextInt(4) + 1; } } </integer></integer>
点赞 回复 分享
发布于 03-14 10:36 湖北
补充一个百度的,两个线程和队列模拟TCP三次握手
点赞 回复 分享
发布于 01-23 08:23 四川
别卷了别卷了
点赞 回复 分享
发布于 2024-12-11 22:09 广东
第八题是➗2再✖️三吗
点赞 回复 分享
发布于 2024-12-11 21:31 北京
接口怎么知道自己的响应时间,它自己能做全链路?
点赞 回复 分享
发布于 2024-12-11 16:41 广东
点赞 回复 分享
发布于 2024-12-11 15:36 四川

相关推荐

JWT&nbsp;的工作原理用户通过用户名和密码等凭据进行身份验证。服务器验证用户的凭据,生成&nbsp;JWT,并将其返回给用户。JWT&nbsp;通过&nbsp;Base64Url&nbsp;编码而成。用户存储&nbsp;JWT,通常存储在浏览器的&nbsp;localStorage&nbsp;或&nbsp;sessionStorage&nbsp;中。用户在每次请求时将&nbsp;JWT&nbsp;发送到服务器,通常通过&nbsp;HTTP&nbsp;请求的&nbsp;Authorization&nbsp;头部。服务器接收到&nbsp;JWT&nbsp;后验证其签名与内容。如果有效,服务器执行该请求;如果无效,返回相应的错误信息。JWT&nbsp;的优势无状态:JWT&nbsp;以自包含的方式存储用户信息,服务器不需要存储用户会话信息,适合分布式系统。跨域支持:由于&nbsp;JWT&nbsp;是基于标准的字符串格式,可以轻松支持跨域请求。灵活性:可以在&nbsp;Token&nbsp;中存储自定义数据,不仅限于身份验证相关的信息。安全性:通过签名算法保证数据的完整性,避免被篡改。JWT&nbsp;的缺点不可撤销性:JWT&nbsp;一旦生成,无法简单地撤销,除非设计了&nbsp;Token&nbsp;刷新机制。过期管理:需要合理设置过期时间,过长会带来安全隐患,过短则可能影响用户体验。隐私问题:JWT&nbsp;中的信息是Base64Url编码的,并未加密,因此敏感信息不应直接放在&nbsp;Token&nbsp;中。常见用例用户身份验证:用户登录成功后,会话管理通过发放&nbsp;JWT&nbsp;实现。API&nbsp;访问控制:保护&nbsp;API&nbsp;端点,确保只有持有有效&nbsp;Token&nbsp;的用户才能访问。单点登录(SSO):多个系统之间共享&nbsp;JWT,实现单点登录。
点赞 评论 收藏
分享
评论
70
435
分享

创作者周榜

更多
牛客网
牛客企业服务