查看原文
其他

Java并发面试,幸亏有点道行,不然又被忽悠了

白头雁 终端研发部 2022-08-26

【公众号回复“1024”,送你一个特别推送】

对于我们来时,Java基础是多么的重要!面试的时候有时候被问得一脸懵逼,二脸懵逼,三两懵逼的。最近我也打算学习java了,有兴趣的童鞋可以参考《终于,我还是下决心学Java后台了》好好总结,只有总结才是王道,只有总结才能提高,来吧,我们一起看一下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个线程卡死计算机。

内存模型,也说点简单的

  1、栈(stack)函数加载的时候,为函数内部变量分配的空间。和父函数的内部变量和运行指针共享同一块区域。

  2、函数运行时,new的空间,都是放在堆中的。

这个就是C的内存模型,做shellcode的基础知识。有面试题可以留言,欢迎一起讨论!

来自作者:白头雁 | 原文链接:

https://www.jianshu.com/p/8cb84ce74548

阅读更多

终于,我还是码造一个了中国地图

SVG前戏—让你的View多姿多彩

分享几个Android很强势的的开源框架

(Android)面试题级答案(精选版)

相信自己,没有做不到的,只有想不到的

在这里获得的不仅仅是技术!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存