() {

@Override

public String call() throws Exception {

return "你好,callable";

}

};

//支持泛型

FuturefutureCallable = executorService.submit(callable);

try {

System.out.println(futureCallable.get());

} catch (InterruptedException e) {

e.printStackTrace();

} catch (ExecutionException e) {

e.printStackTrace();

}

Runnable runnable = new Runnable() {

@Override

public void run() {

System.out.println("你好呀,runnable");

}

};

Future> futureRunnable = executorService.submit(runnable);

try {

System.out.println(futureRunnable.get());

} catch (InterruptedException e) {

e.printStackTrace();

} catch (ExecutionException e) {

e.printStackTrace();

}

executorService.shutdown();

}

}

```

运行结果:

```

你好,callable

你好呀,runnable

null

```

### 16、wait(),notify()和suspend(),resume()之间的区别

* wait() 使得线程进入阻塞等待状态,并且释放锁

* notify()唤醒一个处于等待状态的线程,它一般跟wait()方法配套使用。

* suspend()使得线程进入阻塞状态,并且不会自动恢复,必须对应的resume() 被调用,才能使得线程重新进入可执行状态。suspend()方法很容易引起死锁问题。

* resume()方法跟suspend()方法配套使用。

「suspend()不建议使用」,suspend()方法在调用后,线程不会释放已经占有的资 源(比如锁),而是占有着资源进入睡眠状态,这样容易引发死锁问题。

## 17.Condition接口及其实现原理

* Condition接口与Object监视器方法对比

* Condition接口使用demo

* Condition实现原理

### Condition接口与Object监视器方法对比

Java对象(Object),提供wait()、notify(),notifyAll() 系列方法,配合synchronized,可以实现等待/通知模式。而Condition接口配合Lock,通过await(),signal(),signalAll() 等方法,也可以实现类似的等待/通知机制。

对比项对象监视方法Condition

前置条件获得对象的锁调用Lock.lock()获取锁,调用Lock.newCondition()获得Condition对象

调用方式直接调用,object.wait()直接调用,condition.await()

等待队列数1个多个

当前线程释放锁并进入等待状态支持支持

在等待状态中不响应中断不支持支持

当前线程释放锁并进入超时等待状态支持支持

当前线程释放锁并进入等待状态到将来的某个时间不支持支持

唤醒等待队列中的一个线程支持支持

唤醒等待队列中的全部线程支持支持

### Condition接口使用demo

```

public class ConditionTest {

Lock lock = new ReentrantLock();

Condition condition = lock.newCondition();

public void conditionWait() throws InterruptedException {

lock.lock();

try {

condition.await();

} finally {

lock.unlock();

}

}

public void conditionSignal() throws InterruptedException {

lock.lock();

try {

condition.signal();

} finally {

lock.unlock();

}

}

}

```

### Condition实现原理

其实,同步队列和等待队列中节点类型都是同步器的静态内部类 AbstractQueuedSynchronizer.Node,接下来我们图解一下Condition的实现原理~

「等待队列的基本结构图」

![](https://s4.51cto.com/images/blog/202011/05/97667b6a0a6b44efca473be0789a5416.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)

```

一个Condition包含一个等待队列,Condition拥有首节点(firstWaiter)和尾节点 (lastWaiter)。当前线程调用Condition.await()方法,将会以当前线程构造节点,并将节点从尾部加入等待队

```

「AQS 结构图」

ConditionI是跟Lock一起结合使用的,底层跟同步器(AQS)相关。同步器拥有一个同步队列和多个等待队列~

![](https://s4.51cto.com/images/blog/202011/05/7e048ca39ac3d7e506f339b4fbd05429.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)

「等待」

![](https://s4.51cto.com/images/blog/202011/05/203aad629ba0888303b4b241913288c1.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)

```

当调用await()方法时,相当于同步队列的首节点(获取了锁的节点)移动到Condition的等待队列中。

```

「通知」

![](https://s4.51cto.com/images/blog/202011/05/cb33d876e615dd80de81f334c5efe0b3.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)

```

调用Condition的signal()方法,将会唤醒在等待队列中等待时间最长的节点(首节点),在 唤醒节点之前,会将节点移到同步队列中。

```

### 18、线程池如何调优,最大数目如何确认?

在《Java Concurrency in Practice》一书中,有一个评估线程池线程大小的公式

```

「Nthreads=NcpuUcpu(1+w/c)」

Ncpu = CPU总核数

```

* Ucpu =cpu使用率,0~1

* W/C=等待时间与计算时间的比率

假设cpu 100%运转,则公式为

```

Nthreads=Ncpu*(1+w/c)

```

「估算的话,酱紫:」

* 如果是「IO密集型应用」(如数据库数据交互、文件上传下载、网络数据传输等等),IO操作一般比较耗时,等待时间与计算时间的比率(w/c)会大于1,所以最佳线程数估计就是 Nthreads=Ncpu*(1+1)= 2Ncpu 。

* 如果是「CPU密集型应用」(如算法比较复杂的程序),最理想的情况,没有等待,w=0,Nthreads=Ncpu。又对于计算密集型的任务,在拥有N个处理器的系统上,当线程池的大小为N+1时,通常能实现最优的效率。所以 Nthreads = Ncpu+1

有具体指参考呢?举个例子

```

比如平均每个线程CPU运行时间为0.5s,而线程等待时间(非CPU运行时间,比如IO)为1.5s,CPU核心数为8,那么根据上面这个公式估算得到:线程池大小=(1+1.5/05)*8 =32。

```

参考了网上这篇文章,写得很棒,有兴趣的朋友可以去看一下哈:

* 根据CPU核心数确定线程池并发线程数[8]

### 19、 假设有T1、T2、T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行?

可以使用「join方法」解决这个问题。比如在线程A中,调用线程B的join方法表示的意思就是**:A等待B线程执行完毕后(释放CPU执行权),在继续执行。**

代码如下:

```

public class ThreadTest {

public static void main(String[] args) {

Thread spring = new Thread(new SeasonThreadTask("春天"));

Thread summer = new Thread(new SeasonThreadTask("夏天"));

Thread autumn = new Thread(new SeasonThreadTask("秋天"));

try

{

//春天线程先启动

spring.start();

//主线程等待线程spring执行完,再往下执行

spring.join();

//夏天线程再启动

summer.start();

//主线程等待线程summer执行完,再往下执行

summer.join();

//秋天线程最后启动

autumn.start();

//主线程等待线程autumn执行完,再往下执行

autumn.join();

} catch (InterruptedException e)

{

e.printStackTrace();

}

}

}

class SeasonThreadTask implements Runnable{

private String name;

public SeasonThreadTask(String name){

this.name = name;

}

@Override

public void run() {

for (int i = 1; i <4; i++) {

System.out.println(this.name + "来了: " + i + "次");

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

```

运行结果:

```

春天来了: 1次

春天来了: 2次

春天来了: 3次

夏天来了: 1次

夏天来了: 2次

夏天来了: 3次

秋天来了: 1次

秋天来了: 2次

秋天来了: 3次

```

### 20. LockSupport作用是?

* LockSupport作用

* park和unpark,与wait,notify的区别

* Object blocker作用?

LockSupport是个工具类,它的主要作用是挂起和唤醒线程, 该工具类是创建锁和其他同步类的基础。

```

public static void park(); //挂起当前线程,调用unpark(Thread thread)或者当前线程被中断,才能从park方法返回

public static void parkNanos(Object blocker, long nanos); // 挂起当前线程,有超时时间的限制

public static void parkUntil(Object blocker, long deadline); // 挂起当前线程,直到某个时间

public static void park(Object blocker); //挂起当前线程

public static void unpark(Thread thread); // 唤醒当前thread线程

```

看个例子吧:

```

public class LockSupportTest {

public static void main(String[] args) {

CarThread carThread = new CarThread();

carThread.setName("劳斯劳斯");

carThread.start();

try {

Thread.currentThread().sleep(2000);

carThread.park();

Thread.currentThread().sleep(2000);

carThread.unPark();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

static class CarThread extends Thread{

private boolean isStop = false;

@Override

public void run() {

System.out.println(this.getName() + "正在行驶中");

while (true) {

if (isStop) {

System.out.println(this.getName() + "车停下来了");

LockSupport.park(); //挂起当前线程

}

System.out.println(this.getName() + "车还在正常跑");

try {

Thread.sleep(1000L);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

public void park() {

isStop = true;

System.out.println("停车啦,检查酒驾");

}

public void unPark(){

isStop = false;

LockSupport.unpark(this); //唤醒当前线程

System.out.println("老哥你没酒驾,继续开吧");

}

}

}

```

运行结果:

```

劳斯劳斯正在行驶中

劳斯劳斯车还在正常跑

劳斯劳斯车还在正常跑

停车啦,检查酒驾

劳斯劳斯车停下来了

老哥你没酒驾,继续开吧

劳斯劳斯车还在正常跑

劳斯劳斯车还在正常跑

劳斯劳斯车还在正常跑

劳斯劳斯车还在正常跑

劳斯劳斯车还在正常跑

劳斯劳斯车还在正常跑

```

LockSupport的park和unpark的实现,有点类似wait和notify的功能。但是

```

* park不需要获取对象锁

* 中断的时候park不会抛出InterruptedException异常,需要在park之后自行判断中断状态

* 使用park和unpark的时候,可以不用担心park的时序问题造成死锁

* LockSupport不需要在同步代码块里

* unpark却可以唤醒一个指定的线程,notify只能随机选择一个线程唤醒

```

Object blocker作用?

```

方便在线程dump的时候看到具体的阻塞对象的信息。

```

## 公众号

![](https://s4.51cto.com/images/blog/202011/05/95082e7d73a8256ca6b08a61fdc1806f.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)

## 参考与感谢

* 《java并发编程的艺术》

* 杂谈 什么是伪共享(false sharing)?[9]

* 根据CPU核心数确定线程池并发线程数[10]

* LockSupport的用法及原理[11]

* 探讨缓存行与伪共享

## Reference

```

[1]

个人珍藏的80道多线程并发面试题(1-10答案解析):

https://juejin.im/post/6854573221258199048

[2]

源码角度分析-newFixedThreadPool线程池导致的内存飙升问题:

https://juejin.im/post/6844903930502070285

[3]

面试必备:Java线程池解析:

https://juejin.im/post/6844903889678893063

[4]

Java程序员面试必备:Volatile全方位解析:

https://juejin.im/post/6859390417314512909

[5]

CAS乐观锁解决并发问题的一次实践:

https://juejin.im/post/6844903869340712967#comment

[6]

AQS解析与实战:

https://juejin.im/post/6844903903188746247

[7]

Java程序员面试必备:Volatile全方位解析:

https://juejin.im/post/6859390417314512909

[8]

根据CPU核心数确定线程池并发线程数:

https://www.cnblogs.com/dennyzhangdd/p/6909771.html

[9]

杂谈 什么是伪共享(false sharing)?:

https://juejin.im/post/6844903841964507150

[10]

根据CPU核心数确定线程池并发线程数:

https://www.cnblogs.com/dennyzhangdd/p/6909771.html

[11]

LockSupport的用法及原理:

https://www.jianshu.com/p/f1f2cd289205

```

47道计算机网络面试题,个人珍藏的80道多线程并发面试题(11-20答案解析)相关推荐

  1. 【2021最新版】Java多线程并发面试题总结(108道题含答案解析)

    文章目录 JAVA并发知识库 1.Java中实现多线程有几种方法? 2.继承Thread类 3.实现Runnable接口. 4.ExecutorService.Callable.Future有返回值线 ...

  2. 唯一约束判断 细微差mysql别_50道MySQL面试题,查漏补缺看你掌握多少?(附答案解析)...

    1.MySQL 中有哪几种锁? 1.表级锁:开销小,加锁快:不会出现死锁:锁定粒度大,发生锁冲突的概率最 高,并发度最低. 2.行级锁:开销大,加锁慢:会出现死锁:锁定粒度最小,发生锁冲突的概率最 低 ...

  3. Java架构师面试题系列之Dubbo面试专题(29题,含详细答案解析)

    [Java架构师面试网]收集整理了几乎整个架构师学习途中会遇到的面试题,希望大家都能早日圆自己的架构师梦~ 网站近期在备案和迁移服务器,暂时无法打开,先关注一波公众号吧 公众号:Java架构师面试网, ...

  4. Java架构师面试题系列之Mybatis面试专题(36题,含详细答案解析)

    [Java架构师面试网]收集整理了一些Java面试的常见问题,这些问题可能会在你下一次技术面试中遇到.想成为Java架构师,这些都是不可避免也是必须要掌握的哦,对于其他模块的面试题,我后续也将单独分享 ...

  5. 【2021最新版】MongoDB面试题总结(95道题含答案解析)

    文章目录 1.MongoDB是什么? 2.MongoDB有哪些特点? 3.你说的NoSQL数据库是什么意思?NoSQL与RDBMS直接有什么区别?为什么要使用和不使用NoSQL数据库?说一说NoSQL ...

  6. 【2022最新版】MongoDB面试题总结(95道题含答案解析)

    文章目录 1.MongoDB是什么? 2.MongoDB有哪些特点? 3.你说的NoSQL数据库是什么意思?NoSQL与RDBMS直接有什么区别?为什么要使用和不使用NoSQL数据库?说一说NoSQL ...

  7. linux sed面试题,【2021最新版】Linux面试题总结(48道题含答案解析)

    文章目录 1.绝对路径用什么符号表示?当前目录.上层目录用什么表示?主目录用什么表示? 切换目录用什么命令? 2.怎么查看当前进程?怎么执行退出?怎么查看当前路径? 3.怎么清屏?怎么退出当前命令?怎 ...

  8. Android中高级进阶开发面试题冲刺合集(七)

    以下主要针对往期收录的面试题进行一个分类归纳整理,方便大家统一回顾和参考.本篇是第七集~ 强调一下:因篇幅问题:文中只放部分内容,全部面试开发文档需要的可在公众号<Android苦做舟>获 ...

  9. 【2021最新版】Mysql面试题总结(115道题含答案解析)

    文章目录 1.MySQL中有哪几种锁? 2.MySQL中有哪些不同的表格? 3.简述在MySQL数据库中MyISAM和InnoDB的区别. 4.MySQL中InnoDB支持的四种事务隔离级别名称,以及 ...

最新文章

  1. python使用缩进作为语法边界、一般建议缩进()_Python百题计划
  2. centos mysql5.7主从同步配置_centos7搭建mysql5.7主从同步
  3. 注册表修改之USB口启用
  4. C++中的空类,编译器默认可以产生哪些成员函数
  5. leetcode 519. Random Flip Matrix | 519. 随机翻转矩阵(洗牌算法Fisher–Yates shuffle)
  6. 设计模式--1(设计模式基础,设计模式基本原则,设计模式分类)
  7. C++primer 第 2 章 变量和基本类型
  8. LeetCode 旋转数组 系列
  9. Struts2 多方法的Action
  10. 请简述什么是spring的ioc和di_Spring的IoC与DI的理解
  11. php多线程实现抓取,php使用pthreads v3多线程实现抓取新浪新闻信息操作示例
  12. 如何在Internet Explorer 10中修改缓存行为
  13. 3dmax塌陷在哪里?怎么用?
  14. ubuntu虚拟机使用笔记——9、vmware卸载,重新安装ubuntu,重安后不能共享文件
  15. TranslateMessage()介绍
  16. 服务注册中心之Eureka简介及原理
  17. 新装Ubuntu18.04调校笔记
  18. unityplayerpre存档_c# unity PlayerPrefs 游戏存档,直白点就是讲游戏数据本地保存下来...
  19. 监控器怎样连接到云服务器,一步步教你使用云端服务器yeelink远程监控
  20. IDL常见问题与总结

热门文章

  1. iOS 屏幕适配浅谈
  2. 把阿里旺旺的图标放到你自己的网站上,直接点击按钮就可以让顾客联系到你
  3. premiere消除红眼_如何修复红眼-使用Photoshop CC从图片中消除红眼
  4. OSPF FA地址分析
  5. 谷歌浏览器如何安装插件
  6. 知物由学 | AI与黑产的攻守之道,详解攻击类文字图像的检测
  7. 图形学 (-)数学基础
  8. 数栈产品分享:干货解读数据中台产品「模块化」设计思路
  9. Springboot + Spring Security 实现前后端分离登录认证及权限控制
  10. 天翼网关超级密码获取器