博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java并发面试,幸亏有点道行,不然又被忽悠了
阅读量:6502 次
发布时间:2019-06-24

本文共 2017 字,大约阅读时间需要 6 分钟。

hot3.png

前言

面试Java,必然要被问Java内存模型和Java并发开发。我被问到的时候,心里慌得一批,“额,是在《Thinking in Java》里面写的吗?果然每天增删改太low了”

要了解这些图吗?

我希望能解释的再简单一些,以上都不用

Java 并发代码

 
  1. public class Example1 {
  2. public static int count = 0;
  3. public static int clientTotal = 5000;
  4. public static void main(String[] args) throws Exception {
  5. ExecutorService executorService = Executors.newCachedThreadPool();
  6. for (int i = 0; i < clientTotal ; i++) {
  7. executorService.execute(() -> {
  8. try {
  9. add();
  10. } catch (Exception e) {
  11. log.error("exception", e);
  12. }
  13. });
  14. }
  15. }
  16. private static void add() {
  17. count++;
  18. }
  19. }

如果上面代码执行,count的值是多少?(为了说明重点问题,没有写最后打印的代码) 5000?多次运行的结果,count的值是小于5000的。

解释一下上面的程序,首先定义了一个线程池,启动5000个线程执行add()操作,add函数处理静态成员变量count。

如果程序顺序调用,count的值应该是5000。

 
  1. for(int i=0;i<5000;i++){
  2. add();
  3. }

但是线程池启动多线程,是并发执行的。每个线程启动之后,不管是否运行结束,下一个线程会马上启动。

启动线程的过程,是一个异步过程,启动线程立即返回,启动下一个进程。

当多个线程对同一个变量add进行操作的时候,就会发生写写冲突。

线程1、线程2 同时对值为0的变量进行操作,结果返回1,而不是2。如果这个地方想不明白,就请留言,或者看看文章顶部那些原理图。

要不简单点,记住“多线程对全局变量的写操作会发生冲突”。

答案,声明原子变量 AtomicInteger count

 
  1. public class CountExample2 {
  2.  
  3. // 请求总数
  4. public static int clientTotal = 5000;
  5.  
  6. // 同时并发执行的线程数
  7. public static int threadTotal = 200;
  8.  
  9. public static AtomicInteger count = new AtomicInteger(0);
  10.  
  11. public static void main(String[] args) throws Exception {
  12. ExecutorService executorService = Executors.newCachedThreadPool();
  13. final Semaphore semaphore = new Semaphore(threadTotal);
  14. final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
  15. for (int i = 0; i < clientTotal ; i++) {
  16. executorService.execute(() -> {
  17. try {
  18. semaphore.acquire();
  19. add();
  20. semaphore.release();
  21. } catch (Exception e) {
  22. log.error("exception", e);
  23. }
  24. countDownLatch.countDown();
  25. });
  26. }
  27. countDownLatch.await();
  28. executorService.shutdown();
  29. log.info("count:{}", count.get());
  30. }
  31. private static void add() {
  32. count.incrementAndGet();
  33. // count.getAndIncrement();
  34. }
  35. }

注,上面的代码用了生成者消费者模式,5000个生产者,200个消费者,对程序并发做一定限制,防止5000个线程卡死计算机。

内存模型,也说点简单的

    1. 栈(heap),函数加载的时候,为函数内部变量分配的空间。和父函数的内部变量和运行指针共享同一块区域。
    1. 函数运行时,new的空间,都是放在堆中的。

这个就是C的内存模型,做shellcode的基础知识。

转载于:https://my.oschina.net/u/3954808/blog/3049461

你可能感兴趣的文章
PHP通过读取DOM抓取信息
查看>>
DICOM医学图像处理:DICOM网络传输
查看>>
nio和传统Io的区别
查看>>
移动端网页布局中需要注意事项以及解决方法总结
查看>>
(原创)Linux下查看系统版本号信息的方法
查看>>
oracle
查看>>
redis使用过程中主机内核层面的一些优化
查看>>
我也要谈谈大型网站架构之系列(2)——纵观历史演变(下)
查看>>
大话设计模式(Golang) 二、策略模式
查看>>
使用PostgreSQL 9.6 架设mediawiki服务器
查看>>
数据库服务器硬件对性能的影响
查看>>
LVM
查看>>
windows+群辉服务器环境下,搭建git版本管理
查看>>
Ubuntu 修改源
查看>>
php 几个比较实用的函数
查看>>
(译)OpenGL ES2.0 – Iphone开发指引
查看>>
@RestController 与 @RequestMapping
查看>>
黑马程序员.bobo.DAY.1
查看>>
Unity shader 官网文档全方位学习(二)
查看>>
pbrun
查看>>