💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] # 1. 并发工具 ## 1.1. 并发应用方法和使用场景 | 应用方法 | 使用场景 | | --- | --- | | java.util.concurrent.ConcurrentHashMap、java.util.concurrent.CopyOnWriteArrayList:创建并发容器、线程安全访问并发容器 | 多线程情况下的数据共享和协同处理  | |java.util.concurrent.ThreadPoolExecutor、java.util.concurrent.Executors :创建线程池、提交任务、关闭线程池| 多线程情况下的任务处理和资源管理|  |java.util.concurrent.atomic.AtomicInteger、java.util.concurrent.atomic.AtomicLong:创建原子变量、线程安全访问原子变量| 多线程情况下的变量更新和同步| |java.util.concurrent.locks.ReentrantLock、java.util.concurrent.locks.ReentrantReadWriteLock :创建锁、获取锁、释放锁|多线程情况下的共享资源访问控制 |  |java.util.concurrent.CountDownLatch、java.util.concurrent.CyclicBarrier、java.util.concurrent.Semaphore、java.util.concurrent.Exchanger :创建并发工具类、使用并发工具类| 多线程情况下的同步和通信| ## 1.2. Java 并发工具包列表 | 技术边界 | 特性 | 使用场景 | 应用方法 | 项目结构关系 | 实施关键流程 | | --- | --- | --- | --- | --- | --- | | 并发容器 | 支持高并发读写操作 | 多线程情况下的数据共享和协同处理 | java.util.concurrent.ConcurrentHashMap、java.util.concurrent.CopyOnWriteArrayList | 与项目中的数据结构和算法相关 | 创建并发容器、线程安全访问并发容器 | | 线程池 | 支持线程池的创建和管理 | 多线程情况下的任务处理和资源管理 | java.util.concurrent.ThreadPoolExecutor、java.util.concurrent.Executors | 与项目中的任务调度和资源管理相关 | 创建线程池、提交任务、关闭线程池 | | 原子变量 | 支持线程安全的原子操作 | 多线程情况下的变量更新和同步 | java.util.concurrent.atomic.AtomicInteger、java.util.concurrent.atomic.AtomicLong | 与项目中的数据共享和协同处理相关 | 创建原子变量、线程安全访问原子变量 | | 锁 | 支持线程同步和互斥访问 | 多线程情况下的共享资源访问控制 | java.util.concurrent.locks.ReentrantLock、java.util.concurrent.locks.ReentrantReadWriteLock | 与项目中的资源和数据访问控制相关 | 创建锁、获取锁、释放锁 | | 并发工具类 | 支持高级并发编程操作 | 多线程情况下的同步和通信 | java.util.concurrent.CountDownLatch、java.util.concurrent.CyclicBarrier、java.util.concurrent.Semaphore、java.util.concurrent.Exchanger | 与项目中的并发编程和通信相关 | 创建并发工具类、使用并发工具类 | ## 1.3. 应用场景: * 并发容器:需要在多线程情况下进行数据共享和协同处理的场景,如缓存管理、数据统计和日志记录等。 * 线程池:需要进行多线程任务处理和资源管理的场景,如网络服务、数据处理和计算密集型任务等。 * 原子变量:需要进行线程安全的原子操作的场景,如计数器、标志位和统计数据等。 * 锁:需要进行线程同步和互斥访问的场景,如共享资源的访问控制、线程间的协同处理等。 * 并发工具类:需要进行高级并发编程操作和线程间通信的场景,如等待多个线程完成某项操作、线程间交换数据等。 ## 1.4. 特性: * 并发容器:支持高并发读写操作,具有较高的性能和可扩展性。 * 线程池:支持线程池的创建和管理,可以提高多线程任务处理的效率和可靠性。 * 原子变量:支持线程安全的原子操作,可以提高多线程共享变量的安全性和性能。 * 锁:支持线程同步和互斥访问,可以提高多线程访问共享资源的安全性和可靠性。 * 并发工具类:支持高级并发编程操作和线程间通信,可以提高多线程协同处理的效率和可靠性。 ## 1.5. 应用方法: * 并发容器:使用ConcurrentHashMap、CopyOnWriteArrayList等类创建并发容器,使用put()、get()等方法进行线程安全的读写操作。 * 线程池:使用ThreadPoolExecutor、Executors等类创建线程池,使用submit()、execute()等方法提交任务,使用shutdown()、shutdownNow()等方法关闭线程池。 * 原子变量:使用AtomicInteger、AtomicLong等类创建原子变量,使用get()、set()等方法进行线程安全的读写操作。 * 锁:使用ReentrantLock、ReentrantReadWriteLock等类创建锁,使用lock()、unlock()等方法获取和释放锁,使用tryLock()、tryLock(long time, TimeUnit unit)等方法进行可中断的锁操作。 * 并发工具类:使用CountDownLatch、CyclicBarrier、Semaphore、Exchanger等类创建并发工具类,使用await()、release()、exchange()等方法进行线程间的同步和通信操作。 ## 1.6. 项目结构关系: * 并发工具包中的类和方法可以与项目中的数据结构和算法相关,如使用ConcurrentHashMap存储和管理缓存、使用ThreadPoolExecutor执行任务等。 * 并发工具包中的类和方法可以与项目中的任务调度和资源管理相关,如使用线程池管理网络服务、使用Semaphore控制并发访问资源等。 * 并发工具包中的类和方法可以与项目中的数据共享和协同处理相关,如使用AtomicInteger统计数据、使用CountDownLatch等待多个线程完成某项操作等。 * 并发工具包中的类和方法可以与项目中的资源和数据访问控制相关,如使用锁控制多线程访问共享资源、使用CyclicBarrier协同多个线程进行数据处理等。 * 并发工具包中的类和方法可以与项目中的并发编程和通信相关,如使用Exchanger交换数据、使用Semaphore进行信号量控制等。 ## 1.7. 实施关键流程: * 并发容器:创建并发容器、使用线程安全的读写操作访问并发容器。 * 线程池:创建线程池、提交任务、关闭线程池。 * 原子变量:创建原子变量、使用线程安全的读写操作访问原子变量。 * 锁:创建锁、获取锁、释放锁。 * 并发工具类:创建并发工具类、使用并发工具类进行同步和通信操作。 ## 1.8. 示例 一个经典的并发工具包应用示例是使用线程池和并发容器实现多线程爬虫程序。 ``` import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicInteger; public class MultiThreadCrawler { private static final int MAX_THREADS = 10; // 最大线程数 private static final int MAX_PAGES = 1000; // 最大爬取页面数 private static final String SEED_URL = "https://www.example.com"; // 起始URL private ExecutorService threadPool; // 线程池 private ConcurrentHashMap<String, Integer> visitedUrls; //已访问过的URL集合,使用ConcurrentHashMap实现线程安全的读写操作 private ConcurrentLinkedQueue<String> unvisitedUrls; // 待访问的URL队列,使用ConcurrentLinkedQueue实现线程安全的读写操作 private AtomicInteger pageCount; // 已访问页面计数器,使用AtomicInteger实现线程安全的原子操作 public MultiThreadCrawler() { threadPool = Executors.newFixedThreadPool(MAX_THREADS); visitedUrls = new ConcurrentHashMap<>(); unvisitedUrls = new ConcurrentLinkedQueue<>(); pageCount = new AtomicInteger(0); } public void start() { unvisitedUrls.offer(SEED_URL); // 将起始URL加入待访问队列 while (pageCount.get() < MAX_PAGES && !unvisitedUrls.isEmpty()) { String url = unvisitedUrls.poll(); // 取出待访问队列中的URL if (visitedUrls.containsKey(url)) { continue; // 已经访问过该URL,跳过 } visitedUrls.put(url, 1); // 将该URL添加到已访问集合中 threadPool.submit(new PageFetcher(url, this)); // 提交页面下载任务到线程池 } threadPool.shutdown(); // 关闭线程池} public void incrementPageCount() { pageCount.incrementAndGet(); // 计数器原子自增 } public static void main(String[] args) { MultiThreadCrawler crawler = new MultiThreadCrawler(); crawler.start(); } } class PageFetcher implements Runnable { private String url; private MultiThreadCrawler crawler; public PageFetcher(String url, MultiThreadCrawler crawler) { this.url = url; this.crawler = crawler; } @Override public void run() { // 下载页面并处理数据 // ... // 将新的URL添加到待访问队列 for (String newUrl : newUrls) { crawler.unvisitedUrls.offer(newUrl); // 使用ConcurrentLinkedQueue的offer()方法实现线程安全的添加操作 } crawler.incrementPageCount(); // 已访问页面计数器自增 } } ``` 在上述示例中,使用了线程池和并发容器来实现多线程爬虫程序。 1. 线程池使用了`newFixedThreadPool()`方法创建固定大小的线程池,控制最大线程数不超过10个。 2. 并发容器使用了`ConcurrentHashMap`和`ConcurrentLinkedQueue`来实现线程安全的读写操作,分别用于存储已访问过的URL集合和待访问的URL队列。 3. 在`start()`方法中,首先将起始URL加入待访问队列, 4. 然后在循环中取出待访问队列中的URL, 5. 如果该URL已经访问过,则跳过, 6. 否则将该URL添加到已访问集合中,并提交页面下载任务到线程池。 7. 下载页面的任务在`PageFetcher`类中实现, 8. 下载完成后将新的URL添加到待访问队列中,并将已访问页面计数器自增。 通过使用线程池和并发容器,多线程爬虫程序可以高效地爬取大量的数据,并支持高并发读写操作,提高了程序的可靠性和性能。