当前位置: 首页 > news >正文

惠州百优做网站小程序熊掌号网站改版提案

惠州百优做网站小程序熊掌号,网站改版提案,wordpress页面导航条,成都工商注册核名查询系统《关于并发编程的面试笔记》1.Synchronized和Volatile关键词1.1 Synchronized和Volatile的异同同:都是Java中的关键词,都可实现线程同步异:①volatile 关键字只能用于单个变量,而synchronized适用于方法及代码块②volatile 关键字…

《关于并发编程的面试笔记》

1.Synchronized和Volatile关键词

1.1 Synchronized和Volatile的异同

同:都是Java中的关键词,都可实现线程同步

异:

volatile 关键字只能用于单个变量,而synchronized适用于方法及代码块

②volatile 关键字能保证数据的可见性,但不能保证数据的原子性。synchronized 关键字两者都能保证。

volatile 关键字主要用于解决单个变量在多个线程之间的可见性,而 synchronized 关键字解决的是多线程之间的资源同步

1.2 volatile的使用原理

volatile 可以确保对某个变量的更新对其他线程马上可见 ,一个变量被声明为volatile时,线程在写入变量时不会把值缓存在寄存器或者其他地方,而是会把值刷新回主内存,当其他线程读取该共享变量,会从主内存获取最新值,而不是使用当前线程的本地内存值。

1.3 用途区别

synchronized用于控制代码块/方法的线程安全访问,使用于资源共享

volatile用于状态控制(如线程停止标志)

2.多线程实现的四种方式?

根据是否可获取返回值分为两种!

不可获取返回值:继承Thread类,实现Runnable接口(本质都是重写run()方法

可获取返回值:实现Callable接口,线程池

2.1 继承Thread类

public class MyThread extends Thread {public void run() {while (true) {System.out.println(this.getName() + " is running");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}public static void main(String[] args) {MyThread t1 = new MyThread();MyThread t2 = new MyThread();MyThread t3 = new MyThread();t1.start();t2.start();t3.start();}}

2.2 实现Runnable接口

实现Runnable接口的实现类的实例对象作为Thread构造函数的target

public class TicketSailTask implements Runnable {public static int number = 100;//总共100张票public Object lock = new Object();//创建锁@Overridepublic void run() {while (true) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}synchronized(lock) {if (number > 0) {System.out.println(Thread.currentThread().getName() + "正在卖第" + number + "张票");number--;} else {break;}}}}public static void main(String[] args) {TicketSailTask ticketSailTask = new TicketSailTask();// 三个线程ticketSailTask,共用一个锁对象new Thread(ticketSailTask,"小志").start();// 使用锁对象:ticketSailTask.classnew Thread(ticketSailTask,"小庄").start();// 使用锁对象:ticketSailTask.classnew Thread(ticketSailTask,"小王").start();// 使用锁对象:ticketSailTask.class}}

2.3 Callable和Future Task

特点:可获取到返回值!FutureTask通常只能被执行一次

FutureTask的get()用于阻塞主线程直至获取到执行结果

public class CallableImpl implements Callable<String> {String acceptStr;public CallableImpl(String acceptStr) {this.acceptStr = acceptStr;}@Overridepublic String call() throws Exception {// 任务阻塞一秒Thread.sleep(1000);return this.acceptStr+"添加字段并返回";}public static void main(String[] args) throws ExecutionException, InterruptedException {CallableImpl myTest1 = new CallableImpl("线程1");CallableImpl myTest2 = new CallableImpl("线程2");CallableImpl myTest3 = new CallableImpl("线程3");FutureTask<String> task1 = new FutureTask<>(myTest1);FutureTask<String> task2 = new FutureTask<>(myTest2);FutureTask<String> task3 = new FutureTask<>(myTest3);long beginTime = System.currentTimeMillis();// 创建线程new Thread(task1,"线程1").start();new Thread(task2,"线程2").start();new Thread(task3,"线程3").start();List resultList = new ArrayList<>();// 调用get()阻塞主线程,反之,线程不会阻塞String result1 = task1.get();String result2 = task2.get();String result3 = task3.get();resultList.add(result1);resultList.add(result2);resultList.add(result3);long endTime = System.currentTimeMillis();System.out.println("开始: " + resultList);System.out.println("用时 : " + (endTime - beginTime)/1000 + "s");}
}
开始: [线程1添加字段并返回, 线程2添加字段并返回, 线程3添加字段并返回]
用时 : 1s

2.4 线程池创建线程

注意:线程池记得使用后关闭,避免造成资源泄漏

public class ThreadPool {// 定义要创建的线程数private static int THREAD_NUM=10;public static void main(String[] args) throws InterruptedException {// 线程池有5个固定线程ExecutorService executorService = Executors.newFixedThreadPool(5);for (int i = 0; i < THREAD_NUM; i++) {RunnableThread thread = new RunnableThread();Thread.sleep(1000);executorService.execute(thread);}// todo 关闭线程池executorService.shutdown();}static class RunnableThread implements Runnable{@Overridepublic void run() {System.out.println("通过线程池方式创建的线程:" + Thread.currentThread().getName() + " ");}}
}

3. 项目中哪些地方用到了多线程?

略......

3.1 CountDownLatch的用法

原理:多线程进行递减计数,等到计数到0的时候等待即不再阻塞,从而向下执行。

await()当前线程阻塞,直至计数器到0主线程才可以启动。

/*** @author zzp* @date 2025/9/15/周一 10:42* @description: 主线程主动阻塞等待子线程执行结束再继续执行的案例 -- 使用CountDownLatch()*/public class CountDownLatchDemo {// 创建一个CountDownLatch实例private static volatile CountDownLatch countDownLatch = new CountDownLatch(2);public static void main(String[] args) throws InterruptedException {Thread thread1 = new Thread(new Runnable() {public void run() {try{Thread.sleep(1000);System.out.println("线程1结束");}catch (Exception e){e.printStackTrace();}finally {countDownLatch.countDown();}}});Thread thread2 = new Thread(new Runnable() {public void run() {try {Thread.sleep(1000);System.out.println("线程2结束");}catch (Exception e){e.printStackTrace();}finally {countDownLatch.countDown();}}});// 开启两个子线程thread1.start();thread2.start();System.out.println("主线程等待子线程结束...");countDownLatch.await();System.out.println("所有子线程结束......");}}
主线程等待子线程结束...
线程2结束
线程1结束
所有子线程结束......

CountdownLatch实现多线程并可获取到返回值

异步多线程实现导出写表操作,使用CountDownLatch.await( )实现子线程执行完毕,主线程结束阻塞操作......

    @Overridepublic void exportToExcel(HttpServletResponse response, HbCusReportDto hrd, Map<String, Object> headMap, String fileNamePrefix, String exportFormat) {// TODO 获取数据数量 totalDataSize// TODO 计算需要多少批次 numPages // TODO 获取表头// TODO 设置导出文件名// TODO 根据导出的文件格式-设置响应头信息// 创建线程池,最大线程数为 numPages,假设每个分页查询由一个线程处理// 用于存放查询结果的列表,使用一个 Map 保证顺序 -- allDataListMapMap<Integer, List<List<Object>>> allDataListMap = new TreeMap<>();try (ExcelWriter writer = EasyExcel.write(response.getOutputStream()).excelType(ExcelTypeEnum.XLSX).build()) {// 使用 CountDownLatch 等待所有线程执行完成CountDownLatch latch = new CountDownLatch((int) numPages);// 使用线程提交分页查询任务for (int pageIndex = 0; pageIndex < numPages; pageIndex++) {final int finalPageIndex = pageIndex + 1;long finalPageSize = pageSize;myThreadPool.submit(() -> {try {Map<String, Object> map = selectPageByCondition(hrd.getId(), hrd.getSqlStr(), hrd.getFieldList(), hrd.getParamsList(), (int) finalPageIndex, finalPageSize, hrd.getUserId(), hrd.getWarehouse());IPage<Map<String, String>> iPage = (IPage<Map<String, String>>) map.get("data");List<List<Object>> dataList = ExcelUnits.convertToDataList(iPage.getRecords(), headMap);// 保证按页号顺序存储allDataListMap.put(finalPageIndex, dataList);} catch (Exception e) {log.error("Error during page query for page {}", finalPageIndex, e);} finally {latch.countDown();}});}latch.await();  // ***等待所有分页任务完成***// 按照页号顺序处理查询结果并写入 Excelint currentSheetIndex = 0;int currentSheetDataCount = 0;for (List<List<Object>> dataList : allDataListMap.values()) {if (currentSheetDataCount + dataList.size() > maxRowsPerSheet) {currentSheetIndex++;currentSheetDataCount = 0;}String sheetName = "Sheet" + (currentSheetIndex + 1);WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).head(headList).registerWriteHandler(new CustomWidthStyleStrategy(1)).build();writer.write(dataList, writeSheet);currentSheetDataCount += dataList.size();}} catch (IOException | InterruptedException e) {log.error("Error during export process.", e);Thread.currentThread().interrupt(); // 恢复线程中断状态}}

3.2 使用阻塞队列实现顺序消费

案例:(手机)生产-打包-发运-消费 的顺序执行

--------------------------------------------------Phone手机实体类--------------------------------------------------

public class Phone {/*** 手机的状态* PRODUCED:已生产* PACKED:已打包* DELIVERED:已发货*/public enum Status{PRODUCED,PACKED,DELIVERED}// 默认状态--已生产private Status status = Status.PRODUCED;private final int id;public Phone(int id) {this.id = id;}public void pack(){status = Status.PACKED;}public void deliver(){status = Status.DELIVERED;}public int getId(){return id;}public Status getStatus(){return status;}@Overridepublic String toString() {return "Phone id: " + id + ", status: " + status;    }
}

--------------------------------------------------阻塞队列Queue--------------------------------------------------

public class PhoneQueue extends LinkedBlockingQueue<Phone> {
}

--------------------------------------------------生产手机的任务线程--------------------------------------------------

public class Producer implements Runnable {private PhoneQueue phoneQueue;private int count = 0;private Random random = new Random(47);public Producer(PhoneQueue phoneQueue) {this.phoneQueue = phoneQueue;}@Overridepublic void run() {try {while (!Thread.interrupted()) {TimeUnit.MICROSECONDS.sleep(300 + random.nextInt(500));// 生产有序的手机Phone phone = new Phone(count++);System.out.println(phone);phoneQueue.add(phone);}}catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("Producer is off");}}

--------------------------------------------------打包手机的任务线程--------------------------------------------------

take(): 获取并移除此队列的头部,在元素变得可用之前一直等待 。queue的长度 == 0 的时候,一直阻塞,直到获取到元素值,程序继续......

public class Packer implements Runnable{private PhoneQueue producedQueue;private PhoneQueue packedQueue;public Packer(PhoneQueue producedQueue, PhoneQueue packedQueue) {this.producedQueue = producedQueue;this.packedQueue = packedQueue;}@Overridepublic void run() {try{while(!Thread.interrupted()){// 在取得下一个手机之前会一直阻塞Phone phone = producedQueue.take();phone.pack();System.out.println(phone);packedQueue.put(phone);}}catch(InterruptedException e){System.out.println("Packer thread interrupted");}System.out.println("Packer done");}
}

--------------------------------------------------发运手机的任务线程--------------------------------------------------

public class Delivery implements Runnable {private PhoneQueue packedQueue;private PhoneQueue finishQueue;public Delivery(PhoneQueue packedQueue, PhoneQueue finishQueue) {this.packedQueue = packedQueue;this.finishQueue = finishQueue;}@Overridepublic void run() {try{while (!Thread.interrupted()) {Phone phone = packedQueue.take();phone.deliver();System.out.println(phone);finishQueue.put(phone);}}catch (InterruptedException e){System.out.println("Delivery interrupted");}System.out.println("Delivery off");}
}

--------------------------------------------------消费手机的任务线程--------------------------------------------------

public class Consumer implements Runnable {private PhoneQueue finishedQueue;private int count = 0;public Consumer(PhoneQueue finishedQueue) {this.finishedQueue = finishedQueue;}@Overridepublic void run() {try{while (!Thread.interrupted()) {Phone phone = finishedQueue.take();if (phone.getId() != count++|| phone.getStatus() != Phone.Status.DELIVERED){System.out.println("Error -> " + phone);System.exit(-1);}else {System.out.println(phone + " -> User");}}}catch (InterruptedException e){System.out.println("Consumer interrupted");}System.out.println("Consumer off");}
}

-----------------------------------------------------------主线程-------------------------------------------------------------

public class ConsumerMain {public static void main(String[] args) {PhoneQueue producedQueue = new PhoneQueue();PhoneQueue packedQueue = new PhoneQueue();PhoneQueue deliveredQueue = new PhoneQueue();ExecutorService executor = Executors.newCachedThreadPool();executor.execute(new Producer(producedQueue));executor.execute(new Packer(producedQueue,packedQueue));executor.execute(new Delivery(packedQueue,deliveredQueue));executor.execute(new Consumer(deliveredQueue));try{TimeUnit.SECONDS.sleep(5);}catch (InterruptedException e){e.printStackTrace();}executor.shutdown();}
}

================================结果====================================

Phone id: 0, status: PRODUCED
Phone id: 0, status: PACKED
Phone id: 0, status: DELIVERED
Phone id: 0, status: DELIVERED -> User
Phone id: 1, status: PRODUCED
Phone id: 1, status: PACKED
Phone id: 1, status: DELIVERED
Phone id: 1, status: DELIVERED -> User
......

4. 多线程同步的方案

synchronized关键词:

5. 为什么使用线程池?线程池的优缺点?

-- 避免频繁创建线程和销毁线程(使线程复用)

线程池的优点:

1.降低资源消耗-通过重复利用已创建的线程降低线程创建和销毁造成的资源消耗

2.提高响应速度-任务可以不需要等待线程创建就能立刻执行

3.提高线程的可管理性-线程池可以进行统一的分配,调优和监控

缺点:多线程会占CPU,使用多线程的地方并发量比较高时会导致其他功能响应很慢。  

http://www.dtcms.com/a/512048.html

相关文章:

  • 设计基于LLM的MCP工具:智能工具选择与DAG执行流程
  • 第三方软件课题结题验收测试机构【使用JMeter的Web应用负载测试】
  • 网站建设时间进度表模板wordpress批量修改链接
  • 如何做视频网站赚钱孙俪做的网站广告
  • 华为od-22届考研-测试面经
  • 深度学习卷积层
  • 网页设计模板图片素材下载重庆公司seo
  • 网站先做移动站在做pc站可行吗工程服务建设网站
  • C++第十三篇:继承
  • GD32F407VE天空星开发板SPI配置详解
  • 公司网站建设优帮云企业网站建设需注意什么
  • 垂直原理:宇宙的沉默法则与万物运动的终极源头
  • 如何在没有 iCloud 的情况下备份 iPhone
  • 江苏专业网站建设ps软件手机版
  • 番禺制作网站平台女孩学电子商务专业好就业吗
  • 自动点焊机——为电动自行车打造稳定动力
  • 栈与队列:数据结构中的双雄对决
  • Jenkins 安装,自动化全方位详解文档
  • 第八节_PySide6基本窗口控件_按钮类控件(QAbstractButton)
  • iBizModel 工作流(PSWORKFLOW)模型体系详解
  • 装修公司网站源码网站怎样做免费优化有效果
  • 20.1 ChatPPT v3.0颠覆发布:多模态图像识别+AI生成,办公效率提升500%的核心拆解
  • 【PyTorch】单目标检测部署
  • 3D超点(3D Superpoint)概念解释与代码实现
  • TPAMI 2025 | 从分离到融合:新一代3D场景技术实现双重能力提升!
  • malloc/free 内存问题
  • 国企集团门户网站建设方案有什么做数学题的网站
  • CredentialProvider多用户登录实现
  • ‘/‘ 和 ‘./‘在Vite中的区别
  • 技术指南:如何高效地将SOLIDEDGE模型转换为3DXML格式