1. Java中的ThreadLocal
是什么?它的作用是什么?
答案:
ThreadLocal
是Java提供的一种线程局部变量存储机制,用于为每个线程绑定一个独立的变量副本。- 它的作用是解决多线程环境下的变量共享问题,避免线程安全问题,同时减少锁的使用,提高性能。
- 示例:
输出结果:public class ThreadLocalExample { private static final ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 0); public static void main(String[] args) { Runnable task = () -> { int value = threadLocal.get(); threadLocal.set(value + 1); System.out.println(Thread.currentThread().getName() + ": " + threadLocal.get()); }; Thread t1 = new Thread(task, "Thread-1"); Thread t2 = new Thread(task, "Thread-2"); t1.start(); t2.start(); } }
每个线程都有自己的Thread-1: 1 Thread-2: 1
ThreadLocal
变量副本,互不干扰。
2. 如何在Java中实现线程的优雅关闭?
答案:
- 线程的优雅关闭需要确保线程在退出前完成当前任务,并释放资源。
- 可以通过以下方式实现:
- 使用
volatile
标志位:public class GracefulShutdown { private volatile boolean running = true; public void start() { Thread thread = new Thread(() -> { while (running) { // 执行任务 System.out.println("Thread is running..."); try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); // 重新设置中断状态 System.out.println("Thread interrupted."); } } System.out.println("Thread stopped."); }); thread.start(); // 模拟停止线程 try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } running = false; thread.interrupt(); // 如果线程正在阻塞状态,需要中断它 } public static void main(String[] args) { new GracefulShutdown().start(); } }
- 使用
ExecutorService
的shutdown()
方法:ExecutorService executor = Executors.newSingleThreadExecutor(); executor.submit(() -> { while (!Thread.currentThread().isInterrupted()) { System.out.println("Task is running..."); try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); // 重新设置中断状态 } } }); executor.shutdown(); // 停止接收新任务,等待现有任务完成 try { if (!executor.awaitTermination(60, TimeUnit.SECONDS)) { executor.shutdownNow(); // 强制中断线程 } } catch (InterruptedException e) { executor.shutdownNow(); }
- 使用
3. Java中的ConcurrentHashMap
是如何实现线程安全的?
答案:
ConcurrentHashMap
是Java提供的线程安全的哈希表实现,它通过分段锁(Segment Lock)或CAS操作(Compare-And-Swap)来实现线程安全。- 在Java 8及之前版本中,
ConcurrentHashMap
使用分段锁机制,将整个哈希表分成多个段(Segment),每个段是一个独立的锁,从而减少了锁的粒度,提高了并发性能。 - 在Java 8及之后版本中,
ConcurrentHashMap
引入了CAS操作和synchronized
锁的结合,进一步优化了性能。 - 示例:
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>(); map.put("key1", 1); map.put("key2", 2); System.out.println(map.get("key1")); // 输出:1
4. 如何在Java中实现线程池的自定义拒绝策略?
答案:
- 线程池的拒绝策略用于处理任务队列满且线程池达到最大线程数时的情况。
- Java提供了几种默认的拒绝策略,如
AbortPolicy
、CallerRunsPolicy
等,也可以自定义拒绝策略。 - 示例:
在这个例子中,当任务被拒绝时,会调用自定义的import java.util.concurrent.*; public class CustomRejectedExecutionHandler implements RejectedExecutionHandler { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { System.out.println("Task rejected: " + r); // 自定义处理逻辑,例如记录日志、丢弃任务等 } public static void main(String[] args) { ThreadPoolExecutor executor = new ThreadPoolExecutor( 2, 4, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(2), new CustomRejectedExecutionHandler() ); for (int i = 0; i < 10; i++) { executor.submit(() -> { try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } System.out.println("Task executed by " + Thread.currentThread().getName()); }); } executor.shutdown(); } }
CustomRejectedExecutionHandler
,打印任务被拒绝的信息。
5. Java中的ForkJoinPool
是什么?它如何实现并行计算?
答案:
ForkJoinPool
是Java提供的一个用于并行计算的线程池,它基于分治思想(Divide and Conquer)实现任务的分解和合并。- 它通过
RecursiveTask
或RecursiveAction
类来定义可分解的任务,任务会被分解成多个子任务,直到子任务足够小,可以直接计算结果。 - 示例:
在这个例子中,import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveTask; public class ForkJoinExample extends RecursiveTask<Integer> { private final int[] array; private final int start; private final int end; public ForkJoinExample(int[] array, int start, int end) { this.array = array; this.start = start; this.end = end; } @Override protected Integer compute() { if (end - start <= 10) { // 任务足够小,直接计算 int sum = 0; for (int i = start; i < end; i++) { sum += array[i]; } return sum; } else { // 分解任务 int mid = (start + end) / 2; ForkJoinExample leftTask = new ForkJoinExample(array, start, mid); ForkJoinExample rightTask = new ForkJoinExample(array, mid, end); leftTask.fork(); // 异步执行左任务 int rightResult = rightTask.compute(); // 同步执行右任务 int leftResult = leftTask.join(); // 等待左任务完成并获取结果 return leftResult + rightResult; } } public static void main(String[] args) { int[] array = new int[100]; for (int i = 0; i < array.length; i++) { array[i] = i + 1; } ForkJoinPool pool = new ForkJoinPool(); ForkJoinExample task = new ForkJoinExample(array, 0, array.length); int result = pool.invoke(task); System.out.println("Sum: " + result); // 输出:Sum: 5050 } }
ForkJoinExample
类继承了RecursiveTask
,定义了任务的分解和合并逻辑。ForkJoinPool
负责执行任务并管理线程。