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());
}
