Java并发面试,幸亏有点道行,不然又被忽悠了
面试Java,必然要被问Java内存模型和Java并发开发。我被问到的时候,心里慌得一批,“额,是在《Thinking in Java》里面写的吗?果然每天增删改太low了”
要了解这些图吗?
我希望能解释的再简单一些,以上都不用
Java 并发代码
public class Example1 {
public static int count = 0;
public static int clientTotal = 5000;
public static void main(String[] args) throws Exception {
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < clientTotal ; i++) {
executorService.execute(() -> {
try {
add();
} catch (Exception e) {
log.error("exception", e);
}
});
}
}
private static void add() {
count++;
}
}
如果上面代码执行,count的值是多少?(为了说明重点问题,没有写最后打印的代码)
5000?多次运行的结果,count的值是小于5000的。
解释一下上面的程序,首先定义了一个线程池,启动5000个线程执行add()操作,add函数处理静态成员变量count。
如果程序顺序调用,count的值应该是5000。
for(int i=0;i<5000;i++){
add();
}
但是线程池启动多线程,是并发执行的。每个线程启动之后,不管是否运行结束,下一个线程会马上启动。
启动线程的过程,是一个异步过程,启动线程立即返回,启动下一个进程。
当多个线程对同一个变量add进行操作的时候,就会发生写写冲突。
线程1、线程2 同时对值为0的变量进行操作,结果返回1,而不是2。如果这个地方想不明白,就请留言,或者看看文章顶部那些原理图。
要不简单点,记住“多线程对全局变量的写操作会发生冲突”。
答案,声明原子变量 AtomicInteger count
public class CountExample2 {
// 请求总数
public static int clientTotal = 5000;
// 同时并发执行的线程数
public static int threadTotal = 200;
public static AtomicInteger count = new AtomicInteger(0);
public static void main(String[] args) throws Exception {
ExecutorService executorService = Executors.newCachedThreadPool();
final Semaphore semaphore = new Semaphore(threadTotal);
final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
for (int i = 0; i < clientTotal ; i++) {
executorService.execute(() -> {
try {
semaphore.acquire();
add();
semaphore.release();
} catch (Exception e) {
log.error("exception", e);
}
countDownLatch.countDown();
});
}
countDownLatch.await();
executorService.shutdown();
log.info("count:{}", count.get());
}
private static void add() {
count.incrementAndGet();
// count.getAndIncrement();
}
}
注,上面的代码用了生成者消费者模式,5000个生产者,200个消费者,对程序并发做一定限制,防止5000个线程卡死计算机。
内存模型,也说点简单的
- 栈(heap),函数加载的时候,为函数内部变量分配的空间。和父函数的内部变量和运行指针共享同一块区域。
- 函数运行时,new的空间,都是放在堆中的。
这个就是C的内存模型,做shellcode的基础知识。
有面试题可以留言,一起讨论。
关注公众号
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
-
上一篇
w2 有秒计时的数字时钟
题目内容: 这一周的编程题是需要你在课程所给的时钟程序的基础上修改而成。但是我们并不直接给你时钟程序的代码,请根据视频自己输入时钟程序的Display和Clock类的代码,然后来做这个题目。 我们需要给时钟程序加上一个表示秒的Display,然后为Clock增加以下public的成员函数: public Clock(int hour, int minute, int second); 用hour, minute和second初始化时间。 public void tick(); “嘀嗒”一下,时间走1秒。 public String toString(); 返回一个String的值,以“hh:mm:ss“的形式表示当前时间。这里每个数值都占据两位,不足两位时补0。如“00:01:22"。注意其中的冒号是西文的,不是中文的。 提示:String.format()可以用和printf一样的方式来格式化一个字符串。 另外写一个Main类,它的main函数为下面的样子,注意,必须原封不动地作为Main的main函数: public static void main(String[] args) ...
-
下一篇
Java 基础 之 入门HelloWorld
http://www.verejava.com/?id=1699251664916 import java.lang.*; /** @author : 胡杨 @version : 1.0 1. //双斜杠代表注释, 是给人看的, 机器忽略不计 2. public 公有的, 是java 的关键字 3. class 叫 类, 每一个java文件里必须包含一个类 4. HelloWord 叫 类名, 类名可以跟文件名不一样, 但是规范一般写成一样 5. static 叫 静态的, main方法必须写static java 虚拟机才能找到 6. void 空 也就是没有返回值 7. main 叫主方法, 是java程序的入口, 必须这么写固定的, 否则程序不能运行. 8. String 字符串 是用双引号括起来的数字字符的一连串的组合 9. String[] 字符串数组 10. args 叫 main 方法的参数 11. System: 系统, out : 输出 println : 打印 12. 类名 后面{}部分叫做 类体 括号必须成对出现 13. 主方法main 后面 {} 部分叫做方法体...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS关闭SELinux安全模块
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Docker容器配置,解决镜像无法拉取问题
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- Crontab安装和使用

微信收款码
支付宝收款码