JUC知识点总结

JUC应用场景

1. 网页服务器处理并发请求

当一个网页服务器需要处理大量并发请求时,可以使用多线程来提高处理效率。

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
​
public class WebServer {public static void main(String[] args) throws IOException {ServerSocket serverSocket = new ServerSocket(8080);while (true) {Socket clientSocket = serverSocket.accept();new Thread(new ClientHandler(clientSocket)).start();}}
}
​
class ClientHandler implements Runnable {private Socket clientSocket;
​public ClientHandler(Socket socket) {this.clientSocket = socket;}
​@Overridepublic void run() {try {// 处理客户端请求clientSocket.getOutputStream().write("HTTP/1.1 200 OK\r\n\r\nHello, World!".getBytes());clientSocket.close();} catch (IOException e) {e.printStackTrace();}}
}

2. 文件下载器

多线程下载可以加快大文件的下载速度。

import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
​
public class MultiThreadedDownloader {public static void main(String[] args) throws Exception {String fileURL = "http://example.com/file.zip";int numThreads = 4;new MultiThreadedDownloader().downloadFile(fileURL, numThreads);}
​public void downloadFile(String fileURL, int numThreads) throws Exception {URL url = new URL(fileURL);HttpURLConnection conn = (HttpURLConnection) url.openConnection();int fileSize = conn.getContentLength();conn.disconnect();
​int partSize = fileSize / numThreads;RandomAccessFile file = new RandomAccessFile("downloaded_file.zip", "rw");
​for (int i = 0; i < numThreads; i++) {int start = i * partSize;int end = (i == numThreads - 1) ? fileSize : (start + partSize - 1);new Thread(new DownloadThread(fileURL, start, end, file)).start();}}
}
​
class DownloadThread implements Runnable {private String fileURL;private int start;private int end;private RandomAccessFile file;
​public DownloadThread(String fileURL, int start, int end, RandomAccessFile file) {this.fileURL = fileURL;this.start = start;this.end = end;this.file = file;}
​@Overridepublic void run() {try {HttpURLConnection conn = (HttpURLConnection) new URL(fileURL).openConnection();String range = "bytes=" + start + "-" + end;conn.setRequestProperty("Range", range);conn.connect();byte[] buffer = new byte[1024];int bytesRead;try (RandomAccessFile partFile = new RandomAccessFile(file.getFD(), "rw")) {partFile.seek(start);while ((bytesRead = conn.getInputStream().read(buffer, 0, 1024)) != -1) {partFile.write(buffer, 0, bytesRead);}}conn.disconnect();} catch (Exception e) {e.printStackTrace();}}
}

3. 线程池处理任务

使用线程池管理多线程任务,避免频繁创建和销毁线程带来的开销。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
​
public class ThreadPoolExample {public static void main(String[] args) {ExecutorService executor = Executors.newFixedThreadPool(4);
​for (int i = 0; i < 10; i++) {executor.submit(new Task(i));}
​executor.shutdown();try {if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {executor.shutdownNow();}} catch (InterruptedException e) {executor.shutdownNow();}}
}
​
class Task implements Runnable {private int taskId;
​public Task(int id) {this.taskId = id;}
​@Overridepublic void run() {System.out.println("Executing Task " + taskId + " by " + Thread.currentThread().getName());try {Thread.sleep(2000);  // 模拟任务执行} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Completed Task " + taskId);}
}

4. 生产者-消费者模型

在实际业务中,生产者-消费者模型常用于任务调度、消息队列等场景。

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
​
public class ProducerConsumerExample {public static void main(String[] args) {BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);
​Thread producerThread = new Thread(new Producer(queue));Thread consumerThread = new Thread(new Consumer(queue));
​producerThread.start();consumerThread.start();}
}
​
class Producer implements Runnable {private BlockingQueue<Integer> queue;
​public Producer(BlockingQueue<Integer> queue) {this.queue = queue;}
​@Overridepublic void run() {for (int i = 0; i < 20; i++) {try {queue.put(i);System.out.println("Produced: " + i);Thread.sleep(100);  // 模拟生产延迟} catch (InterruptedException e) {e.printStackTrace();}}}
}
​
class Consumer implements Runnable {private BlockingQueue<Integer> queue;
​public Consumer(BlockingQueue<Integer> queue) {this.queue = queue;}
​@Overridepublic void run() {while (true) {try {int value = queue.take();System.out.println("Consumed: " + value);Thread.sleep(150);  // 模拟消费延迟} catch (InterruptedException e) {e.printStackTrace();}}}
}

5. 并行计算

在数据处理和计算任务中,多线程可以显著提高性能。例如,计算一个大数组的总和。

import java.util.concurrent.RecursiveTask;
import java.util.concurrent.ForkJoinPool;
​
public class ParallelSum {private static final int THRESHOLD = 10_000;
​public static void main(String[] args) {int[] array = new int[100_000];for (int i = 0; i < array.length; i++) {array[i] = i + 1;}
​ForkJoinPool forkJoinPool = new ForkJoinPool();Long sum = forkJoinPool.invoke(new SumTask(array, 0, array.length));System.out.println("Sum: " + sum);}
}
​
class SumTask extends RecursiveTask<Long> {private int[] array;private int start;private int end;
​public SumTask(int[] array, int start, int end) {this.array = array;this.start = start;this.end = end;}
​@Overrideprotected Long compute() {if (end - start <= ParallelSum.THRESHOLD) {long sum = 0;for (int i = start; i < end; i++) {sum += array[i];}return sum;} else {int mid = (start + end) / 2;SumTask leftTask = new SumTask(array, start, mid);SumTask rightTask = new SumTask(array, mid, end);
​leftTask.fork();long rightResult = rightTask.compute();long leftResult = leftTask.join();
​return leftResult + rightResult;}}
}

当然可以,下面是一些更多实际业务中应用 Java 多线程技术的场景示例。

6. 定时任务调度

在某些业务场景中,需要定时执行任务,比如定时备份数据库、清理日志等,可以使用多线程来实现定时任务调度。

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
​
public class ScheduledTaskExample {public static void main(String[] args) {ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
​Runnable task = () -> System.out.println("Executing Task at " + System.currentTimeMillis());// 5秒后执行任务,每10秒执行一次scheduler.scheduleAtFixedRate(task, 5, 10, TimeUnit.SECONDS);}
}

7. 并行数据处理

在大数据处理或数据流处理场景中,使用多线程可以显著提高数据处理速度。

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
​
public class ParallelDataProcessing {public static void main(String[] args) {List<String> data = Arrays.asList("data1", "data2", "data3", "data4", "data5");ExecutorService executor = Executors.newFixedThreadPool(3);
​for (String item : data) {executor.submit(() -> processItem(item));}
​executor.shutdown();}
​private static void processItem(String item) {System.out.println("Processing " + item + " by " + Thread.currentThread().getName());try {Thread.sleep(1000);  // 模拟处理时间} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Completed " + item);}
}

8. 异步任务处理

在一些业务场景中,需要执行异步任务以提高系统的响应速度,例如异步处理用户请求等。

import java.util.concurrent.CompletableFuture;
​
public class AsyncTaskExample {public static void main(String[] args) {System.out.println("Main thread: " + Thread.currentThread().getName());
​CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {System.out.println("Async task thread: " + Thread.currentThread().getName());try {Thread.sleep(2000);  // 模拟异步任务处理} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Async task completed");});
​future.thenRun(() -> System.out.println("Continuation task thread: " + Thread.currentThread().getName()));}
}

9. 多线程计算任务

在一些计算密集型任务中,比如矩阵运算、多项式计算等,可以使用多线程提高计算效率。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class MultiThreadedMatrixMultiplication {private static final int MATRIX_SIZE = 3;public static void main(String[] args) {int[][] matrixA = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} };int[][] matrixB = { {9, 8, 7}, {6, 5, 4}, {3, 2, 1} };int[][] result = new int[MATRIX_SIZE][MATRIX_SIZE];ExecutorService executor = Executors.newFixedThreadPool(MATRIX_SIZE);for (int i = 0; i < MATRIX_SIZE; i++) {for (int j = 0; j < MATRIX_SIZE; j++) {executor.submit(new MatrixMultiplicationTask(matrixA, matrixB, result, i, j));}}executor.shutdown();while (!executor.isTerminated()) {}for (int[] row : result) {for (int value : row) {System.out.print(value + " ");}System.out.println();}}
}class MatrixMultiplicationTask implements Runnable {private int[][] matrixA;private int[][] matrixB;private int[][] result;private int row;private int col;public MatrixMultiplicationTask(int[][] matrixA, int[][] matrixB, int[][] result, int row, int col) {this.matrixA = matrixA;this.matrixB = matrixB;this.result = result;this.row = row;this.col = col;}@Overridepublic void run() {for (int k = 0; k < matrixA.length; k++) {result[row][col] += matrixA[row][k] * matrixB[k][col];}}
}

10. 实时数据分析

在金融、物联网等领域,需要实时分析数据,可以使用多线程来提高处理速度。

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;public class RealTimeDataAnalysis {public static void main(String[] args) {BlockingQueue<String> dataQueue = new LinkedBlockingQueue<>();Thread producerThread = new Thread(new DataProducer(dataQueue));Thread consumerThread = new Thread(new DataConsumer(dataQueue));producerThread.start();consumerThread.start();}
}class DataProducer implements Runnable {private BlockingQueue<String> queue;public DataProducer(BlockingQueue<String> queue) {this.queue = queue;}@Overridepublic void run() {for (int i = 0; i < 20; i++) {try {String data = "Data-" + i;queue.put(data);System.out.println("Produced: " + data);Thread.sleep(500);  // 模拟数据生成延迟} catch (InterruptedException e) {e.printStackTrace();}}}
}class DataConsumer implements Runnable {private BlockingQueue<String> queue;public DataConsumer(BlockingQueue<String> queue) {this.queue = queue;}@Overridepublic void run() {while (true) {try {String data = queue.take();System.out.println("Consumed: " + data);Thread.sleep(1000);  // 模拟数据处理时间} catch (InterruptedException e) {e.printStackTrace();}}}
}

JUC核心知识点

Java 并发工具包(Java Concurrency Utilities,简称 JUC)是 Java 提供的一套强大的并发工具,用于简化多线程编程。JUC 位于 java.util.concurrent 包中,包含了多种并发编程的核心工具和类。下面是 JUC 的一些核心知识点以及如何使用这些工具。

1. 基本线程池和任务执行

1.1 Executor 框架

Executor 框架提供了一种将任务提交与任务执行分离的方法。核心接口是 ExecutorExecutorService

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ExecutorExample {public static void main(String[] args) {ExecutorService executor = Executors.newFixedThreadPool(3);for (int i = 0; i < 5; i++) {executor.submit(new Task());}executor.shutdown();}
}class Task implements Runnable {@Overridepublic void run() {System.out.println("Executing Task by " + Thread.currentThread().getName());try {Thread.sleep(2000);  // 模拟任务执行} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Task Completed by " + Thread.currentThread().getName());}
}

2. 同步容器类

2.1 BlockingQueue

BlockingQueue 是一个线程安全的队列,常用于生产者-消费者模型。

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;public class BlockingQueueExample {public static void main(String[] args) {BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);Thread producerThread = new Thread(new Producer(queue));Thread consumerThread = new Thread(new Consumer(queue));producerThread.start();consumerThread.start();}
}class Producer implements Runnable {private BlockingQueue<Integer> queue;public Producer(BlockingQueue<Integer> queue) {this.queue = queue;}@Overridepublic void run() {for (int i = 0; i < 20; i++) {try {queue.put(i);System.out.println("Produced: " + i);Thread.sleep(100);  // 模拟生产延迟} catch (InterruptedException e) {e.printStackTrace();}}}
}class Consumer implements Runnable {private BlockingQueue<Integer> queue;public Consumer(BlockingQueue<Integer> queue) {this.queue = queue;}@Overridepublic void run() {while (true) {try {int value = queue.take();System.out.println("Consumed: " + value);Thread.sleep(150);  // 模拟消费延迟} catch (InterruptedException e) {e.printStackTrace();}}}
}

3. 并发工具类

3.1 CountDownLatch

CountDownLatch 用于使一个或多个线程等待其他线程完成一组操作。

import java.util.concurrent.CountDownLatch;public class CountDownLatchExample {public static void main(String[] args) throws InterruptedException {int count = 3;CountDownLatch latch = new CountDownLatch(count);for (int i = 0; i < count; i++) {new Thread(new Worker(latch)).start();}latch.await();  // 等待所有工作线程完成System.out.println("All workers are done.");}
}class Worker implements Runnable {private CountDownLatch latch;public Worker(CountDownLatch latch) {this.latch = latch;}@Overridepublic void run() {System.out.println("Worker " + Thread.currentThread().getName() + " is working...");try {Thread.sleep(2000);  // 模拟工作} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Worker " + Thread.currentThread().getName() + " done.");latch.countDown();  // 完成工作,计数减一}
}
3.2 CyclicBarrier

CyclicBarrier 用于使一组线程互相等待,直到到达某个公共屏障点。

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;public class CyclicBarrierExample {public static void main(String[] args) {int count = 3;CyclicBarrier barrier = new CyclicBarrier(count, () -> System.out.println("All parties have arrived."));for (int i = 0; i < count; i++) {new Thread(new Worker(barrier)).start();}}
}class Worker implements Runnable {private CyclicBarrier barrier;public Worker(CyclicBarrier barrier) {this.barrier = barrier;}@Overridepublic void run() {System.out.println("Worker " + Thread.currentThread().getName() + " is working...");try {Thread.sleep(2000);  // 模拟工作System.out.println("Worker " + Thread.currentThread().getName() + " reached barrier.");barrier.await();  // 等待其他线程} catch (InterruptedException | BrokenBarrierException e) {e.printStackTrace();}}
}

4. 并发集合类

4.1 ConcurrentHashMap

ConcurrentHashMap 是一个线程安全的哈希表,支持高并发性。

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ConcurrentHashMapExample {public static void main(String[] args) {ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();ExecutorService executor = Executors.newFixedThreadPool(4);for (int i = 0; i < 10; i++) {int index = i;executor.submit(() -> {map.put("key" + index, index);System.out.println("Added: key" + index + " by " + Thread.currentThread().getName());});}executor.shutdown();while (!executor.isTerminated()) {}map.forEach((key, value) -> System.out.println(key + ": " + value));}
}

5. 原子类

5.1 AtomicInteger

AtomicInteger 提供了一种线程安全的方式来更新整数值。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;public class AtomicIntegerExample {public static void main(String[] args) {AtomicInteger counter = new AtomicInteger();ExecutorService executor = Executors.newFixedThreadPool(3);for (int i = 0; i < 10; i++) {executor.submit(() -> {int value = counter.incrementAndGet();System.out.println("Counter: " + value);});}executor.shutdown();}
}

6. Future 和 Callable

FutureCallable 提供了一种异步获取结果的方式。

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;public class FutureCallableExample {public static void main(String[] args) {ExecutorService executor = Executors.newFixedThreadPool(3);Future<Integer> future = executor.submit(new Task());try {Integer result = future.get();  // 获取异步任务结果System.out.println("Result: " + result);} catch (InterruptedException | ExecutionException e) {e.printStackTrace();}executor.shutdown();}
}class Task implements Callable<Integer> {@Overridepublic Integer call() throws Exception {Thread.sleep(2000);  // 模拟计算return 42;}
}

7. ReentrantLock

ReentrantLock 是一种比 synchronized 更灵活的锁机制。

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class ReentrantLockExample {private final Lock lock = new ReentrantLock();public static void main(String[] args) {ReentrantLockExample example = new ReentrantLockExample();Runnable task = example::performTask;Thread t1 = new Thread(task);Thread t2 = new Thread(task);t1.start();t2.start();}public void performTask() {lock.lock();try {System.out.println("Locked by " + Thread.currentThread().getName());Thread.sleep(2000);  // 模拟任务执行} catch (InterruptedException e) {e.printStackTrace();} finally {System.out.println("Unlocked by " + Thread.currentThread().getName());lock.unlock();}}
}

8. 读写锁(ReadWriteLock)

ReadWriteLock 允许多个读线程同时访问,但写线程独占访问。

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;public class ReadWriteLockExample {private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();private int sharedData = 0;public static void main(String[] args) {ReadWriteLockExample example = new ReadWriteLockExample();Runnable readTask = () -> {for (int i = 0; i < 5; i++) {example.readData();try {Thread.sleep(100);  // 模拟读取操作时间} catch (InterruptedException e) {e.printStackTrace();}}};Runnable writeTask = () -> {for (int i = 0; i < 5; i++) {example.writeData(i);try {Thread.sleep(100);  // 模拟写入操作时间} catch (InterruptedException e) {e.printStackTrace();}}};Thread t1 = new Thread(readTask);Thread t2 = new Thread(readTask);Thread t3 = new Thread(writeTask);t1.start();t2.start();t3.start();}public void readData() {readWriteLock.readLock().lock();try {System.out.println(Thread.currentThread().getName() + " Reading: " + sharedData);} finally {readWriteLock.readLock().unlock();}}public void writeData(int data) {readWriteLock.writeLock().lock();try {System.out.println(Thread.currentThread().getName() + " Writing: " + data);sharedData = data;} finally {readWriteLock.writeLock().unlock();}}
}

9. 线程协作

9.1 Semaphore

Semaphore 用于控制同时访问特定资源的线程数量。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;public class SemaphoreExample {private static final int MAX_PERMITS = 3;private final Semaphore semaphore = new Semaphore(MAX_PERMITS);public static void main(String[] args) {SemaphoreExample example = new SemaphoreExample();ExecutorService executor = Executors.newFixedThreadPool(10);for (int i = 0; i < 10; i++) {executor.submit(example::performTask);}executor.shutdown();}public void performTask() {try {semaphore.acquire();System.out.println(Thread.currentThread().getName() + " Acquired permit.");Thread.sleep(2000);  // 模拟任务执行} catch (InterruptedException e) {e.printStackTrace();} finally {System.out.println(Thread.currentThread().getName() + " Released permit.");semaphore.release();}}
}
9.2 Exchanger

Exchanger 用于两个线程之间交换数据。

import java.util.concurrent.Exchanger;public class ExchangerExample {public static void main(String[] args) {Exchanger<String> exchanger = new Exchanger<>();new Thread(new DataProducer(exchanger)).start();new Thread(new DataConsumer(exchanger)).start();}
}class DataProducer implements Runnable {private Exchanger<String> exchanger;public DataProducer(Exchanger<String> exchanger) {this.exchanger = exchanger;}@Overridepublic void run() {try {String data = "Producer Data";System.out.println("Produced: " + data);String receivedData = exchanger.exchange(data);System.out.println("Received by Producer: " + receivedData);} catch (InterruptedException e) {e.printStackTrace();}}
}class DataConsumer implements Runnable {private Exchanger<String> exchanger;public DataConsumer(Exchanger<String> exchanger) {this.exchanger = exchanger;}@Overridepublic void run() {try {String data = "Consumer Data";System.out.println("Produced: " + data);String receivedData = exchanger.exchange(data);System.out.println("Received by Consumer: " + receivedData);} catch (InterruptedException e) {e.printStackTrace();}}
}

10. Fork/Join 框架

Fork/Join 框架用于将大任务拆分成多个小任务并行执行。适用于计算密集型任务。

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;public class ForkJoinExample {public static void main(String[] args) {ForkJoinPool forkJoinPool = new ForkJoinPool();int[] array = new int[100];for (int i = 0; i < array.length; i++) {array[i] = i + 1;}SumTask task = new SumTask(array, 0, array.length);int result = forkJoinPool.invoke(task);System.out.println("Sum: " + result);}
}class SumTask extends RecursiveTask<Integer> {private static final int THRESHOLD = 10;private int[] array;private int start;private int end;public SumTask(int[] array, int start, int end) {this.array = array;this.start = start;this.end = end;}@Overrideprotected Integer compute() {if (end - start <= THRESHOLD) {int sum = 0;for (int i = start; i < end; i++) {sum += array[i];}return sum;} else {int mid = (start + end) / 2;SumTask leftTask = new SumTask(array, start, mid);SumTask rightTask = new SumTask(array, mid, end);leftTask.fork();rightTask.fork();return leftTask.join() + rightTask.join();}}
}

总结

JUC 提供了一系列强大的工具和类,帮助开发者更容易地实现高效的并发程序。在实际开发中,选择合适的并发工具和类,并根据业务需求进行优化,可以显著提升应用程序的性能和响应速度。希望以上示例能够帮助你更好地理解和应用 JUC 的核心知识点。

juc面试

在中国互联网公司中,关于 JUC(Java 并发工具包)的面试题往往涉及到多线程编程的基础知识、线程安全问题以及 JUC 提供的各种工具和类的实际应用。以下是一些常见的面试题示例:

1. 基础概念

  1. 什么是线程安全?如何保证线程安全?

    • 线程安全是指多个线程访问共享资源时,不会导致数据不一致或程序异常。可以通过同步机制(如 synchronized 关键字、Lock 接口)或使用线程安全的类(如 ConcurrentHashMap)来保证线程安全。

  2. 什么是死锁?如何避免死锁?

    • 死锁是指两个或多个线程相互等待对方释放资源,导致程序无法继续执行。避免死锁的方法包括资源排序法、定时锁尝试以及使用高层次的锁机制(如 ReentrantLock)。

2. JUC 工具类

  1. 解释 CountDownLatch 的原理及使用场景。

    • CountDownLatch 是一个同步辅助类,用于使一个或多个线程等待其他线程完成一组操作。常见使用场景包括并行计算中的阶段同步。

    import java.util.concurrent.CountDownLatch;public class CountDownLatchExample {public static void main(String[] args) throws InterruptedException {int count = 3;CountDownLatch latch = new CountDownLatch(count);for (int i = 0; i < count; i++) {new Thread(() -> {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}latch.countDown();}).start();}latch.await();System.out.println("All tasks completed.");}
    }
  2. 解释 CyclicBarrier 的原理及使用场景。

    • CyclicBarrier 是一个同步辅助类,使一组线程相互等待,直到到达某个公共屏障点。常见使用场景包括分段任务的汇总,如多线程分段计算结果的合并。

    import java.util.concurrent.BrokenBarrierException;
    import java.util.concurrent.CyclicBarrier;public class CyclicBarrierExample {public static void main(String[] args) {int count = 3;CyclicBarrier barrier = new CyclicBarrier(count, () -> System.out.println("All parties have arrived."));for (int i = 0; i < count; i++) {new Thread(() -> {try {Thread.sleep(1000);System.out.println(Thread.currentThread().getName() + " reached barrier.");barrier.await();} catch (InterruptedException | BrokenBarrierException e) {e.printStackTrace();}}).start();}}
    }
  3. Semaphore 的使用场景及如何实现限流。

    • Semaphore 用于控制同时访问特定资源的线程数量。常见使用场景包括限流和资源池管理。

    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Semaphore;public class SemaphoreExample {private static final int MAX_PERMITS = 3;private final Semaphore semaphore = new Semaphore(MAX_PERMITS);public static void main(String[] args) {SemaphoreExample example = new SemaphoreExample();ExecutorService executor = Executors.newFixedThreadPool(10);for (int i = 0; i < 10; i++) {executor.submit(example::performTask);}executor.shutdown();}public void performTask() {try {semaphore.acquire();System.out.println(Thread.currentThread().getName() + " Acquired permit.");Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();} finally {System.out.println(Thread.currentThread().getName() + " Released permit.");semaphore.release();}}
    }

3. 线程池

  1. 线程池的工作原理是什么?常见的线程池有哪些?

    • 线程池通过重用已创建的线程来减少线程创建和销毁的开销。常见的线程池包括 FixedThreadPoolCachedThreadPoolScheduledThreadPoolSingleThreadExecutor

  2. 如何自定义线程池?

    • 可以使用 ThreadPoolExecutor 类来自定义线程池,指定核心线程数、最大线程数、空闲线程存活时间、任务队列以及线程工厂和拒绝策略。

    import java.util.concurrent.LinkedBlockingQueue;
    import java.util.concurrent.ThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;public class CustomThreadPool {public static void main(String[] args) {ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 4, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(10));for (int i = 0; i < 10; i++) {executor.execute(() -> {System.out.println(Thread.currentThread().getName() + " is working.");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}});}executor.shutdown();}
    }

4. 原子类和锁

  1. 什么是 CAS?CAS 是如何实现线程安全的?

    • CAS(Compare-And-Swap)是一种原子操作,用于实现无锁并发。它通过比较内存中的值和预期值,如果相等则更新为新值,否则继续重试。

  2. ReentrantLocksynchronized 的区别?

    • ReentrantLock 提供了比 synchronized 更加灵活的锁机制,支持公平锁、非公平锁以及在同一个线程中可以多次获取锁。synchronized 是 Java 内置的同步机制,使用简单但功能有限。

5. 并发编程中的经典问题

  1. 生产者-消费者问题如何解决?

    • 可以使用 BlockingQueueSemaphore 或者自定义锁和条件变量来解决生产者-消费者问题。

  2. 哲学家就餐问题如何解决?

    • 可以使用 ReentrantLock 或者 Semaphore 来解决哲学家就餐问题,避免死锁和饥饿问题。

继续介绍一些关于 JUC 的常见面试题和相关概念,帮助你更好地准备面试。

6. 高级锁机制

6.1 ReadWriteLock 的使用场景和实现原理
  • ReadWriteLock 允许多个读线程同时访问,但写线程独占访问,适用于读多写少的场景。

  • ReentrantReadWriteLockReadWriteLock 的一个实现,提供了 readLockwriteLock

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;public class ReadWriteLockExample {private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();private int sharedData = 0;public void readData() {readWriteLock.readLock().lock();try {System.out.println(Thread.currentThread().getName() + " Reading: " + sharedData);} finally {readWriteLock.readLock().unlock();}}public void writeData(int data) {readWriteLock.writeLock().lock();try {System.out.println(Thread.currentThread().getName() + " Writing: " + data);sharedData = data;} finally {readWriteLock.writeLock().unlock();}}public static void main(String[] args) {ReadWriteLockExample example = new ReadWriteLockExample();Runnable readTask = example::readData;Runnable writeTask = () -> example.writeData(42);new Thread(readTask).start();new Thread(writeTask).start();}
}
6.2 StampedLock 的使用场景和实现原理
  • StampedLock 是一种改进的读写锁,提供了更高的并发性能,尤其是在读多写少的场景下。

  • StampedLock 提供了乐观读锁,允许无锁读取,只有在检测到数据变化时才进行加锁。

import java.util.concurrent.locks.StampedLock;public class StampedLockExample {private final StampedLock stampedLock = new StampedLock();private int sharedData = 0;public void readData() {long stamp = stampedLock.tryOptimisticRead();int data = sharedData;if (!stampedLock.validate(stamp)) {stamp = stampedLock.readLock();try {data = sharedData;} finally {stampedLock.unlockRead(stamp);}}System.out.println(Thread.currentThread().getName() + " Reading: " + data);}public void writeData(int data) {long stamp = stampedLock.writeLock();try {sharedData = data;System.out.println(Thread.currentThread().getName() + " Writing: " + data);} finally {stampedLock.unlockWrite(stamp);}}public static void main(String[] args) {StampedLockExample example = new StampedLockExample();Runnable readTask = example::readData;Runnable writeTask = () -> example.writeData(42);new Thread(readTask).start();new Thread(writeTask).start();}
}

7. 并发集合类

7.1 ConcurrentHashMap 的实现原理和使用
  • ConcurrentHashMap 是线程安全的哈希表,实现了高并发性能。

  • 通过分段锁机制,每个桶有自己的锁,从而减少锁的竞争。

import java.util.concurrent.ConcurrentHashMap;public class ConcurrentHashMapExample {public static void main(String[] args) {ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();map.put("key1", 1);map.put("key2", 2);map.forEach((key, value) -> System.out.println(key + ": " + value));new Thread(() -> map.put("key3", 3)).start();new Thread(() -> System.out.println(map.get("key3"))).start();}
}
7.2 ConcurrentLinkedQueue 的实现原理和使用
  • ConcurrentLinkedQueue 是一个基于无锁算法的线程安全队列,适用于高并发场景。

  • 使用 CAS 操作保证线程安全和高效性。

import java.util.concurrent.ConcurrentLinkedQueue;public class ConcurrentLinkedQueueExample {public static void main(String[] args) {ConcurrentLinkedQueue<Integer> queue = new ConcurrentLinkedQueue<>();queue.add(1);queue.add(2);System.out.println("Queue size: " + queue.size());new Thread(() -> queue.add(3)).start();new Thread(() -> System.out.println(queue.poll())).start();}
}

8. 原子类

8.1 AtomicInteger 的使用场景和实现原理
  • AtomicInteger 提供了一种线程安全的方式来更新整数值,基于 CAS 实现。

  • 常用于计数器和计量器等场景。

import java.util.concurrent.atomic.AtomicInteger;public class AtomicIntegerExample {public static void main(String[] args) {AtomicInteger counter = new AtomicInteger();Runnable task = () -> {for (int i = 0; i < 1000; i++) {counter.incrementAndGet();}};Thread t1 = new Thread(task);Thread t2 = new Thread(task);t1.start();t2.start();try {t1.join();t2.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Counter: " + counter.get());}
}
8.2 AtomicReference 的使用场景和实现原理
  • AtomicReference 提供了一种线程安全的方式来更新对象引用。

  • 常用于需要原子更新复杂对象的场景。

import java.util.concurrent.atomic.AtomicReference;public class AtomicReferenceExample {public static void main(String[] args) {AtomicReference<String> reference = new AtomicReference<>("initial");Runnable task = () -> {for (int i = 0; i < 10; i++) {String oldValue = reference.get();String newValue = oldValue + " updated";reference.compareAndSet(oldValue, newValue);}};Thread t1 = new Thread(task);Thread t2 = new Thread(task);t1.start();t2.start();try {t1.join();t2.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Final value: " + reference.get());}
}

9. 并发问题解决方案

9.1 生产者-消费者问题的解决方案
  • 可以使用 BlockingQueue 实现生产者-消费者模式,简化线程间通信和同步。

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;public class ProducerConsumerExample {public static void main(String[] args) {BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);Thread producer = new Thread(() -> {for (int i = 0; i < 20; i++) {try {queue.put(i);System.out.println("Produced: " + i);} catch (InterruptedException e) {e.printStackTrace();}}});Thread consumer = new Thread(() -> {while (true) {try {int value = queue.take();System.out.println("Consumed: " + value);} catch (InterruptedException e) {e.printStackTrace();}}});producer.start();consumer.start();}
}

10. Fork/Join 框架

10.1 Fork/Join 框架的使用场景和实现原理
  • Fork/Join 框架用于将大任务拆分成多个小任务并行执行,适用于计算密集型任务。

  • 通过 ForkJoinPoolRecursiveTaskRecursiveAction 实现。

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;public class ForkJoinExample {public static void main(String[] args) {ForkJoinPool forkJoinPool = new ForkJoinPool();int[] array = new int[100];for (int i = 0; i < array.length; i++) {array[i] = i + 1;}SumTask task = new SumTask(array, 0, array.length);int result = forkJoinPool.invoke(task);System.out.println("Sum: " + result);}
}class SumTask extends RecursiveTask<Integer> {private static final int THRESHOLD = 10;private int[] array;private int start;private int end;public SumTask(int[] array, int start, int end) {this.array = array;this.start = start;this.end = end;}@Overrideprotected Integer compute() {if (end - start <= THRESHOLD) {int sum = 0;for (int i = start; i < end; i++) {sum += array[i];}return sum;

线程池的数量与系统的 CPU 核心数

Java 线程池的数量设置与系统的 CPU 核心数有很大关系。合理设置线程池的大小可以充分利用系统资源,提高程序的并发性能和响应速度。以下是一些关于如何根据 CPU 核心数来设置线程池数量的原则和方法。

1. CPU 密集型任务

CPU 密集型任务:主要依赖于处理器进行大量计算,常见的任务包括复杂计算、图像处理、加密/解密等。

对于 CPU 密集型任务(即主要消耗 CPU 资源的任务),线程数的设置应接近于 CPU 核心数。这样可以避免过多的线程上下文切换,从而提高 CPU 使用效率。

建议线程数公式:

$$
\text{线程数} = \text{CPU 核心数} + 1
$$

其中,多出来的一个线程是为了应对偶尔的 I/O 操作或者其它非 CPU 密集型操作。

2. I/O 密集型任务

IO 密集型任务:主要依赖于输入输出操作,常见的任务包括文件读写、网络通信、数据库操作等。

对于 I/O 密集型任务(即主要消耗 I/O 资源如文件读写、网络通信的任务),由于 I/O 操作等待时间较长,CPU 会有大量空闲时间,因此可以设置更多的线程来充分利用这些空闲时间。

建议线程数公式:

$$
\text{线程数} = \text{CPU 核心数} \times (1 + \frac{\text{等待时间}}{\text{CPU 时间}})
$$

其中,等待时间是指任务在等待 I/O 操作完成的时间,CPU 时间是指任务实际消耗 CPU 资源的时间。

3. 混合型任务

对于同时包含 CPU 密集型和 I/O 密集型操作的混合型任务,需要根据具体情况进行调优。可以通过分析任务的 CPU 和 I/O 比例,参考上述两种类型任务的线程数计算方法,综合确定合适的线程池大小。

4. 实际案例

假设一个 Windows 系统的 CPU 核心数为 8:

  • CPU 密集型任务:建议线程池大小为 (8 + 1 = 9)。

  • I/O 密集型任务:假设等待时间是 CPU 时间的 10 倍,建议线程池大小为

    $$
    8 \times (1 + \frac{10}{1}) = 88
    $$

     

5. 使用 Runtime.getRuntime().availableProcessors()

在 Java 中,可以使用 Runtime.getRuntime().availableProcessors() 获取系统的 CPU 核心数,并根据上述原则动态设置线程池大小。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadPoolExample {public static void main(String[] args) {int cpuCores = Runtime.getRuntime().availableProcessors();// CPU 密集型任务线程池ExecutorService cpuThreadPool = Executors.newFixedThreadPool(cpuCores + 1);// I/O 密集型任务线程池int ioThreads = cpuCores * (1 + 10); // 假设等待时间是 CPU 时间的 10 倍ExecutorService ioThreadPool = Executors.newFixedThreadPool(ioThreads);// 提交任务示例for (int i = 0; i < 100; i++) {cpuThreadPool.execute(() -> {// CPU 密集型任务performCpuTask();});ioThreadPool.execute(() -> {// I/O 密集型任务performIoTask();});}cpuThreadPool.shutdown();ioThreadPool.shutdown();}private static void performCpuTask() {// 模拟 CPU 密集型任务for (int i = 0; i < 1000000; i++) {Math.sqrt(i);}}private static void performIoTask() {// 模拟 I/O 密集型任务try {Thread.sleep(100); // 模拟 I/O 等待} catch (InterruptedException e) {Thread.currentThread().interrupt();}}
}

6. 监控与调整

实际应用中,线程池大小的设置可能需要根据运行情况进行调整和优化。可以使用监控工具(如 JVisualVM、JProfiler 等)来观察线程池的运行情况,并根据负载和性能表现进行调整。

7. 其它注意事项

  • 线程池的类型:根据具体应用场景选择合适的线程池类型(如 FixedThreadPool, CachedThreadPool, ScheduledThreadPool 等)。

  • 任务队列的类型:根据任务特点选择合适的任务队列(如 LinkedBlockingQueue, ArrayBlockingQueue 等)。

  • 资源限制:考虑系统的内存、I/O 带宽等资源限制,避免设置过大的线程池导致资源争用和性能下降。

通过合理设置线程池的大小,可以有效提高程序的并发性能和资源利用率。希望这些建议和示例代码能对你有所帮助。

Java对象内存布局和加锁机制

Java 对象内存布局

Java 对象在内存中的布局主要包括三个部分:

  1. 对象头(Object Header)

  2. 实例数据(Instance Data)

  3. 对齐填充(Padding)

1. 对象头(Object Header)

对象头由以下两部分组成:

  • Mark Word: 存储对象的运行时数据,如哈希码(hash code)、GC 分代年龄(GC generational age)、锁状态标志(lock state)、偏向锁(biased locking)标志等。

  • Class Pointer: 指向对象的类元数据(Class Metadata),即对象所属的类。

Mark Word

Mark Word 是一个多功能的字段,在不同状态下包含不同的信息。Mark Word 通常占用 32 位或 64 位空间,取决于使用的是 32 位还是 64 位的 JVM。

  • 未锁定(Unlocked)状态:

    • 32 位:对象哈希码、GC 分代年龄

    • 64 位:对象哈希码、GC 分代年龄

  • 偏向锁(Biased Locking)状态:

    • 32 位:线程 ID、Epoch、偏向锁标志

    • 64 位:线程 ID、Epoch、偏向锁标志

  • 轻量级锁(Lightweight Locking)状态:

    • 存储指向栈中锁记录的指针(lock record pointer)

  • 重量级锁(Heavyweight Locking)状态:

    • 存储指向重量级锁(monitor)的指针

  • GC 标记(GC Marking)状态:

    • GC 用于标记对象的标记信息

Class Pointer

Class Pointer 指向对象的类元数据,即对象所属类的定义。这有助于 JVM 在运行时确定对象的类型信息。

2. 实例数据(Instance Data)

实例数据存储的是对象的实际字段值,包括从父类继承下来的字段。实例数据的排列顺序取决于字段在类中的声明顺序以及 JVM 的实现。

3. 对齐填充(Padding)

对齐填充是为了保证对象的大小是 8 字节的倍数(某些 JVM 要求是 16 字节的倍数),以便于内存对齐和访问效率。

加锁的原理

Java 中的锁机制主要包括以下几种:

  1. 无锁(No Lock)

  2. 偏向锁(Biased Locking)

  3. 轻量级锁(Lightweight Locking)

  4. 重量级锁(Heavyweight Locking)

1. 无锁(No Lock)

当对象没有被任何线程锁定时,Mark Word 存储对象的哈希码和 GC 分代年龄。这是对象的初始状态。

2. 偏向锁(Biased Locking)

偏向锁的设计是为了优化只有一个线程访问同步块的情况。当一个线程首次获取偏向锁时,Mark Word 中记录该线程的 ID。如果同一个线程再次进入同步块,无需进行同步操作,可以大大减少开销。当另一个线程尝试获取该锁时,偏向锁会被撤销。

3. 轻量级锁(Lightweight Locking)

轻量级锁使用 CAS(Compare-And-Swap)操作来尝试获取锁。如果获取成功,Mark Word 会记录指向线程栈中锁记录的指针。如果获取失败,会膨胀为重量级锁。轻量级锁适用于锁竞争不激烈的场景。

4. 重量级锁(Heavyweight Locking)

重量级锁使用操作系统的互斥量(Mutex)实现,性能开销较大。当锁竞争激烈时,轻量级锁会膨胀为重量级锁,Mark Word 中记录指向重量级锁(monitor)的指针。

总结

Java 对象内存布局中的对象头和锁机制是 JVM 实现高效并发的关键部分。通过理解这些底层原理,可以更好地优化并发程序的性能和稳定性。

Java内存模型

Java 内存模型(Java Memory Model,JMM)是 Java 虚拟机(JVM)中定义的一组规范,旨在解决多线程程序中共享变量访问的可见性和指令重排序问题。JMM 确保了多线程环境下程序的正确性和一致性。

1. 基本概念

内存可见性

内存可见性是指一个线程对共享变量的修改,何时能被其他线程看到。在多线程程序中,每个线程都有自己的工作内存(工作缓存),用于存储共享变量的副本。JMM 确保了在特定的操作顺序下,线程对共享变量的修改能够被其他线程及时看到。

指令重排序

指令重排序是编译器和处理器为了优化程序性能,对指令顺序进行重新排列。在单线程环境中,重排序不会影响程序的正确性,但在多线程环境中,重排序可能导致不可预期的并发问题。JMM 通过 happens-before 规则来约束指令重排序。

2. JMM 的关键原则

happens-before 关系

happens-before 关系定义了操作之间的顺序性和可见性规则。它确保一个操作的结果对另一个操作是可见的。以下是 happens-before 规则的主要内容:

  • 程序顺序规则: 在一个线程内,按照程序顺序,前面的操作 happens-before 于后面的操作。

  • 监视器锁规则: 对一个锁的解锁 happens-before 于后续对这个锁的加锁。

  • volatile 变量规则: 对一个 volatile 变量的写操作 happens-before 于后续对这个 volatile 变量的读操作。

  • 线程启动规则: 一个线程的 Thread.start() 调用 happens-before 于这个线程内的所有操作。

  • 线程终止规则: 一个线程的所有操作 happens-before 于对这个线程的 Thread.join() 的返回。

  • 传递性: 如果 A happens-before B,且 B happens-before C,则 A happens-before C。

3. volatile 关键字

volatile 关键字提供了一种轻量级的同步机制,确保变量的更新操作对所有线程可见。使用 volatile 变量时,JMM 保证:

  • volatile 变量的写操作会立刻刷新到主内存中。

  • volatile 变量的读操作会从主内存中重新加载最新的值。

  • volatile 变量的读写操作不会与其他内存操作发生重排序。

4. 锁和同步

锁和同步是 JMM 确保内存可见性和指令顺序的核心机制:

synchronized 关键字

synchronized 关键字用于方法或代码块,确保在同一时刻只有一个线程能够执行同步代码。它隐含了两个 happens-before 规则:

  • 对一个锁的解锁 happens-before 于后续对这个锁的加锁。

  • 进入一个 synchronized 代码块前,必须获得锁,而退出这个代码块时必须释放锁。

Lock 接口

Java 提供了 java.util.concurrent.locks.Lock 接口,比 synchronized 更灵活。常用的实现包括 ReentrantLockReadWriteLock。这些锁也遵循 happens-before 规则,确保线程间的内存可见性和操作顺序。

5. 内存屏障

内存屏障(Memory Barrier)是一种硬件指令,用于控制指令执行的顺序和内存操作的可见性。JMM 使用内存屏障来实现 volatile 变量的语义和锁的语义。常见的内存屏障有:

  • LoadLoad Barrier: 确保在屏障前的所有读操作都完成后,才能执行屏障后的读操作。

  • StoreStore Barrier: 确保在屏障前的所有写操作都完成后,才能执行屏障后的写操作。

  • LoadStore Barrier: 确保在屏障前的所有读操作都完成后,才能执行屏障后的写操作。

  • StoreLoad Barrier: 确保在屏障前的所有写操作都完成后,才能执行屏障后的读操作。这是最严格的内存屏障。

6. JMM 对指令重排序的限制

JMM 对指令重排序的限制主要通过以下方式实现:

  • 编译器在编译阶段对代码进行重排序,但必须遵守 happens-before 规则。

  • 处理器在执行阶段对指令进行重排序,但必须遵守内存屏障的约束。

  • Java 内存模型通过对 volatile 变量和同步块的使用来强制内存屏障,确保内存可见性和指令顺序。

7. 实践中的应用

volatile 的使用场景
  • 状态标志:用 volatile 变量作为状态标志,确保线程能够及时看到状态的变化。

  • 单例模式:使用 volatile 变量来实现线程安全的懒汉式单例模式。

public class Singleton {private static volatile Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}
}
synchronized 的使用场景
  • 同步方法或代码块:在多线程环境中保护共享资源,确保线程安全。

  • 经典生产者-消费者模型:使用 synchronized 实现线程间的协调。

class ProducerConsumer {private final LinkedList<Integer> list = new LinkedList<>();private final int CAPACITY = 10;public void produce() throws InterruptedException {int value = 0;while (true) {synchronized (this) {while (list.size() == CAPACITY) {wait();}list.add(value++);notify();}}}public void consume() throws InterruptedException {while (true) {synchronized (this) {while (list.isEmpty()) {wait();}int value = list.removeFirst();notify();}}}
}

总结

Java 内存模型(JMM)通过定义内存可见性和指令重排序的规则,确保了多线程环境下程序的正确性和一致性。理解 JMM 有助于编写高效、安全的并发程序,避免常见的并发问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/52153.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

8月21日笔记

Frp Frp(Fast e Reverse ) Proxy) 是一款简单&#xff0c;好用&#xff0c;稳定的隧道工具。Frp 使用 Go语言开发&#xff0c;支持跨平台&#xff0c;仅需下载对应平台的二进制文件即可执行&#xff0c;没有额外依赖。它是一款高性能的反向代理应用&#xff0c;可以轻松地进行…

Spring DI 数据类型—— set 方法注入

首先新建项目&#xff0c;可参考 初识IDEA、模拟三层--控制层、业务层和数据访问层 一、spring 环境搭建 &#xff08;一&#xff09;pom.xml 导相关坐标 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.or…

http连接未释放导致生产故障

凌晨4点运维老大收到报警&#xff08;公司官网页面超时&#xff0c;上次故障因为运维修改nginx导致官网域名下某些接口不可用后&#xff0c;运维在2台nginx服务器上放了检测程序&#xff0c;检测官网页面&#xff09;&#xff0c;运维自己先看了看服务器相关配置&#xff0c;后…

Java实现STL中的全排列函数next_permutation()

目录 一、引言 二、全排列函数next_permutation() 三、next_permutation()的使用 四、Java实现next_permutation() 五、使用next_permutation()实现全排列 一、引言 相信很多小伙伴们都做过全排列的算法题&#xff0c;输入一个n&#xff0c;输出1~n的全排列。对于这个问题…

k8s相关命令

一、Kubectl是什么 控制K8S通信的命令工具。 格式&#xff1a; kubectl [command] [TYPE] [NAME] [FLAGS] 二、Kubectl命令 1.查看容器命令 kubectl get pod kubectl get pod -n default #查看当前的命名空间的pod kubectl get pod -A #查看所有命名空间的pod kubectl de…

.Net插件开发开源框架

在.NET开发中&#xff0c;有许多开源框架可以用于插件开发&#xff0c;以下是一些最常见的框架&#xff1a; MEF&#xff08;Managed Extensibility Framework&#xff09; MEF是一个用于创建可插拔软件应用程序的库&#xff0c;它可以在不修改原始应用程序的情况下扩展应用程…

JVM 有哪些垃圾回收器?

JVM 有哪些垃圾回收器&#xff1f; 图中展示了7种作用于不同分代的收集器&#xff0c;如果两个收集器之间存在连线&#xff0c;则说明它们可以搭配使用。虚拟机所处的区域则表示它是属于新生代还是老年代收集器。 新生代收集器&#xff08;全部的都是复制算法&#xff09;&…

【安全靶场】-DC-7

❤️博客主页&#xff1a; iknow181 &#x1f525;系列专栏&#xff1a; 网络安全、 Python、JavaSE、JavaWeb、CCNP &#x1f389;欢迎大家点赞&#x1f44d;收藏⭐评论✍ 一、收集信息 1.查看主机是否存活 nmap -T4 -sP 192.168.216.149 2.主动扫描 看开放了哪些端口和功能 n…

【网络】UDP和TCP之间的差别和回显服务器

文章目录 UDP 和 TCP 之间的差别有连接/无连接可靠传输/不可靠传输面向字节流/面向数据报全双工/半双工 UDP/TCP API 的使用UDP APIDatagramSocket构造方法方法 DatagramPacket构造方法方法 回显服务器&#xff08;Echo Server&#xff09;1. 接收请求2. 根据请求计算响应3. 将…

JVM分代回收

JVM分代回收 堆中分为两份:新生代和老年代(1:2) 新生代 新生代的内部分为了三个区域 Eden区,From区,To区[8:1:1] 当eden区内存不足时,就会使用可达性分析算法进行标记 标记eden区和from区的存活对象 将这些对象复制到to区,对eden区和from区进行清除 如果eden下次又出现…

黑马头条vue2.0项目实战(十一)——功能优化(组件缓存、响应拦截器、路由跳转与权限管理)

1. 组件缓存 1.1 介绍 先来看一个问题&#xff1f; 从首页切换到我的&#xff0c;再从我的回到首页&#xff0c;我们发现首页重新渲染原来的状态没有了。 首先&#xff0c;这是正常的状态&#xff0c;并非问题&#xff0c;路由在切换的时候会销毁切出去的页面组件&#xff…

Java之HashMap的底层实现

Java之HashMap的底层实现 摘要HashMap的底层原理哈希值转换为数组下标节点初始化put(Object key, Object value)重写toString()get(Object key)增加泛化remove(K key) 摘要 本博客主要讲述了Java的HashMap的底层实现 HashMap的底层原理 底层原理&#xff1a;数组链表 过程…

【ARM 芯片 安全与攻击 5.6 -- 侧信道与隐蔽信道的区别】

文章目录 侧信道与隐蔽信道的区别侧信道攻击(Side-channel Attack)侧信道攻击简介侧信道攻击 使用方法侧信道攻击示例隐蔽信道(Covert Channel)隐蔽信道简介隐蔽信道使用方法隐蔽信道代码示例侧信道与隐蔽信道在芯片及系统安全方面的使用侧信道的应用隐蔽信道的应用Summary…

【C/C++】菱形继承问题

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;c系列专栏&#xff1a;C/C零基础到精通 &#x1f525; 给大…

python进阶语法---异常处理

在 Python 中&#xff0c;异常处理是一种机制&#xff0c;用于处理程序运行时可能发生的错误&#xff0c;以确保程序能够优雅地处理错误情况&#xff0c;而不是直接崩溃。异常处理机制的核心是使用 try、except、else 和 finally 语句。 一、基础语法 异常处理的基本语法如下…

【JAVA CORE_API】Day18 网络编程、线程、在线聊天室v1.0

C/S&#xff1a;客户端/服务器端&#xff0c;所有网络应用都是基于客户端服务器端进行的&#xff0c;Java写的是服务端&#xff0c;客户端是一个软件&#xff0c;服务端也是一个软件&#xff0c;两个软件之间交互&#xff1b;&#xff08;只能连接对应的服务器&#xff09; B/…

深度学习-k-mean实现聚类

对模拟函数生成的随机数据&#xff0c;分为三个族群。 1.生成数据 设定样本数量、特征数、族群数&#xff0c;以及簇内标准差之后&#xff0c;通过make_blobs生成随机数据。 scikit-learn库中的make_blobs函数来生成模拟数据集的&#xff0c;用于创建多类单标签数据集&#…

吐血整理 ChatGPT 3.5/4.0/4o 新手使用手册~

都知道ChatGPT很强大&#xff0c;聊聊天、写论文、搞翻译、写代码、写文案、审合同等等&#xff0c;无所不能~ 那么到底怎么使用呢&#xff1f;其实很简单了&#xff0c;国内AI产品发展也很快&#xff0c;很多都很好用了~ 我一直在用&#xff0c;建议收藏下来~ 有最先进、最…

基于 Appium 的 App 爬取实战

除了运行 Appium 的基本条件外&#xff0c;还要一个日志输出库 安装&#xff1a; pip install loguru 思路分析 首先我们观察一下整个 app5 的交互流程&#xff0c;其首页分条显示了电影数据&#xff0c; 每个电影条目都包括封面&#xff0c;标题&#xff0c; 类别和评分 4…

Godot《躲避小兵》实战之创建玩家场景

项目设置完之后&#xff0c;我们就可以开始处理玩家控制的角色。 这里我们将玩家放在一个单独的场景当中&#xff0c;这样做的好处是在游戏的其他部分做出来之前&#xff0c;我们就可以对其进行单独测试。 节点结构 场景是一个节点树结构&#xff0c;因此一个场景需要有一个…