java-多线程-一道阿里面试题分析

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

传说这是阿里的一道面试题: 也传说发这道题出来的作者去了tmail。下面是关于题目的描述:

     这段代码大多数情况下运行正常,但是某些情况下会出问题。什么时候会出现什么问题?如何修正?可见博客 http://yueyemaitian.iteye.com/blog/1387901 

Java代码   收藏代码
  1. public class MyStack {  
  2.     private List<String> list = new ArrayList<String>();  
  3.   
  4.     public synchronized void push(String value) {  
  5.         synchronized (this) {  
  6.             list.add(value);  
  7.             notify();  
  8.         }  
  9.     }  
  10.   
  11.     public synchronized String pop() throws InterruptedException {  
  12.         synchronized (this) {  
  13.             if (list.size() <= 0) {  
  14.                 wait();  
  15.             }  
  16.             return list.remove(list.size() - 1);  
  17.         }  
  18.     }  
  19. }  

下面是关于这道题的分析:


   list.remove(list.size() - 1);这句代码有可能引发数组下标越界
原因:
假设其中一种情形呵!出问题的情形可能很多,但原理都差不多。下面的标号代表程序时序的先后顺序。
 1,初始化时list的值为0,然后线程1调用了pop,于是被wait了,然后释放了锁。
 2,线程2调用push,在notify之前有线程3调用pop(记住这时候线程1还没有被唤醒,还在wait住),此时线程3会因为等待锁而挂起,或自旋,反正就是在等待锁可用。
 3,然后线程2继续往下执行,notify被执行(但这时候线程1是不会唤醒的,因为锁还在线程2占用),线程2退出push方法,释放内置锁,此时,线程1和线程3都在内置锁等待队列里面。由于synchronized是没法保证线程竞争的公平性,所以线程1和线程3都可能得到锁。
 4,假设线程1竞争到了锁,不会出问题,正常去除list值,然后remove,执行完后线程3执行,同样被wait住。
 5,假设线程3竞争到了锁,问题来了,线程3会判断到list的size不为0,于是remove,所以list的size就为0了,然后线程 3释放锁,这时候,线程1就得到锁,于是从wait中醒来,继续执行,然后直接调用list的remove,由于list的size=0,那么remove(-1),越界错误就产生了。


   还有同学说两个线程都在wait处等候也会出问题,其实不会出问题的,因为是调用的notify而不是notifyAll,如果是调用notifyAll那么也会出同样的问题。


  至于改进:
  看到这个题目我就很纳闷,为什么要用双重锁,好像没有必要双重锁。我第一眼看到双重锁的时候就在想,出题者是不是在模拟一个套管死锁,我也确实为找这个死锁付出了一些时间。但是这个双重检查都是可重入的锁,都是对于this对象上的锁。所以不存在套管死锁。
改进1,——最小代码改动,就在remove之前再检查list.size==0
改进2,——去掉push和pop方法内的第二重锁检查,我确实没有发现这个锁会有什么用,反而耗性能。 当然这里还是要有方案1的判断(谢谢一楼提醒)
改进3,——重新设计,如果是我来设计这么一个生产者,消费者模式。我更愿意用LinkedBlockingQueue,它有take方法阻塞消费者直到队列可用。而且还有offer方法阻塞生产者直到队列可以插入,可以有效的阻止OOM。

  这个题目出的好,难道是阿里有人犯过这个错误!呵呵!

  关于本题的讨论如有任何纰漏,请大家及时指出呵!

转载于:https://my.oschina.net/u/176507/blog/137880

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/403293.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

简单话题:LED呼吸灯和串口LED指示灯

最近在串口发送引脚上接LED指示发送或者接收状态&#xff0c;但是需求是希望连续发送或者接收字符过程中LED闪烁&#xff0c;而不是保持在一个常量或者常灭的状态。首先&#xff0c;把实际电路图和串口时序贴出来: 可以看出串口发送接收空闲态为高电平&#xff0c;只要进行数据…

mac下使用sshpass实现ssh记住密码

From: http://tinyhema.iteye.com/blog/2093795 由于有一些场景不能使用ssh私钥来实现免登&#xff0c;因此需要想其它办法解决一下这个问题。 安装sshpass 试图使用homebrew安装 Shell代码 $ brew install sshpass Error: No available formula for sshpass We wont …

ESXI忘记密码怎么办?

忘记ESX root用户的密码怎么办? 以单用户模式进入COS&#xff0c;然后修改root密码&#xff0c;既可搞定。第1步&#xff1a;打开/重启ESX主机图1第2步&#xff1a;到GRUB菜单处 (图2) &#xff0c;用键盘上下键&#xff0c;将光标放在“VMware ESX 4.0”上&#xff0c;按“a”…

TCPDUMP/LIBPCAP 1-由零开始

简介 TCPDUMP是强大的网络包分析器&#xff0c;可以在线或离线抓包&#xff0c;设置过滤条件等操作。 LIBPCAP是十分简洁易用的C/C网络流量抓包库&#xff1b;实际上TCPDUMP就是基于LIBPCAP实现的一个应用程序。为什么要学会工具和库的使用 工欲善其事必先利其器&#xff0c…

TCPDUMP/LIBPCAP 2-搭建环境

1. 实验平台   Linux 发行版本众多&#xff0c;考虑到大部分开发者的习惯&#xff0c;因此决定采用桌面版系统&#xff0c;具体为 CentOS-6.5-x86_64。系统内核版本为&#xff1a;2.6.32。尽管内核版本较低&#xff0c;但考虑到兼容性和稳定性&#xff0c;选择了此版本系统作…

使用jquery的blockui插件显示弹出层

使用jquery的blockui插件显示弹出层 Posted on 2011-04-14 16:34 孤独者 阅读(9975) 评论(0) 编辑 收藏 在做网站的开发过程中&#xff0c;可能需要使用弹出层&#xff0c;使用jquery的blockui插件可以很轻松的实现这个效果。blockui可以在你发送ajax请求的时候&#xff0c;显…

提升用户体验,你不得不知道的事儿——三种提醒框的微技巧

大家都知道无论是android开发还是其他的开发&#xff0c;用户的体验都是很重要的事儿&#xff0c;下面就android开发中的三种提醒方式&#xff0c;Toast,SnackBar,Dialog做一些细节上的处理&#xff0c;或许能让你的产品更有用户亲和力。 1&#xff09;Toast Toast是一个轻量级…

el-table列宽设置百分比无效;el-table使用min-width设置百分比;el-table百分比设置无效;

废话不多说&#xff0c;直接给每个el-table-column&#xff0c;设置 width"auto" min-width"25%"即可。 总的百分比还是要等于100%哈。 点赞收藏吧 感谢 代码可以直接复制使用&#xff1a; <template><div style"width:1300px;">&…

VIM使用系统剪切板

在 Linux 终端模式下使用 vim 编辑器时发现经常需要在vim打开的文本文档进行复制粘贴&#xff0c;那么下面就跟着我的思路一步步往下走吧。 一、首先确认当前 vim 配置是不是支持系统剪切板&#xff0c;可以在终端模式下输入命令&#xff1a; vim --version | grep clipboard…

python操作Excel读写--使用xlrd

From: http://www.cnblogs.com/lhj588/archive/2012/01/06/2314181.html 一、安装xlrd模块 到python官网下载http://pypi.python.org/pypi/xlrd模块安装&#xff0c;前提是已经安装了python 环境。 也可以在命令行执行&#xff1a;easy_install xlrd (注意权限) 二、使用介绍…

el-table自动充满,且无滚动条;el-table某列的列宽自适应,其他列按比例分配。

情景一&#xff1a;例如首列按照内容自适应展开&#xff0c;其余列有各自的比例。这样设置&#xff0c;就不会出现滚动条。 注意点&#xff1a; 给需要自适应展开的列加 :width"flexColumnWidth"计算方法 就可以自适应展开需要给余下所有的列都设置 width“auto” mi…

DataGridView控件中显示图片及其注意事项 【z】

windows Forms编程里面有一个DataGridView控件&#xff0c;它不光是可以显示数据&#xff0c;可以显示按钮&#xff0c;复选框&#xff0c;甚至还可以显示图片。这些图片可以来自于数据库&#xff08;用二进制的方式存储的&#xff09;&#xff0c;也可以来自文件系统。下面是一…

在winform上内嵌入其它的程序

这段代码很有意义,用于把一个程序的界面嵌入到我们自己程序的某个指定窗体上. 比如在某个项目里,我需要把基恩士的激光扫描轮廓显示给客户看,但是激光的DLL中并没有这种功能提供. 于是我想先启动激光的官方程序用以显示轮廓, 然后再把这种显示界面嵌入到我自己程序的界面上指定…

SPI总线时序

SPI&#xff0c;是一种高速的&#xff0c;全双工&#xff0c;同步的通信总线&#xff0c;并且在芯片的管脚上只占用四根线&#xff0c;节约了芯片的管脚&#xff0c;同时为PCB的布局上节省空间&#xff0c;提供方便&#xff0c;正是出于这种简单易用的特性&#xff0c;现在越来…

js计算浮点数出现小数;解决js计算小数问题;js数组相加出现小数;

原博1 原博2 方案1和方案2都是有效的 注意参数一定要是数字 而不能是字符串 否则会计算错误 情景&#xff1a; 在计算浮点数时候&#xff0c;出现多余小数。 例如&#xff1a; 1.11 1 2.1100000000000003 为什么计算小数会出现误差&#xff1f; 浮点数值的最高进度是17位…

VMware安装系统时没有弹出分区设置

在安装虚拟机系统的时候&#xff0c;有时候会遇到在安装一些镜像时没有弹出分区设置的画面&#xff0c;比如&#xff0c;我在使用 VMware 安装 CentOS 的时候&#xff0c;在选择完镜像&#xff0c;设置好启动安装的时候系统自动为我划分了 3 个分区&#xff1a;/boot、/、swap分…

如何在postgresql中模拟oracle的dual表,来测试数据库最基本的连接功能?

还好&#xff0c;网上弄到的&#xff0c;&#xff0c;没有dual的数据库&#xff0c;可以试图用select函数不带from数据表的方式来实现返回值。 一段测试代码&#xff1a; try:conn psycopg2.connect(databasedb.service_name, userdb.username, passwordpassword, hostdb.ip, …

vue+element实现树状表格的增删改查;使用el-table树形数据与懒加载实现树状表格增删改查

以下代码可以直接复制使用 一、情景&#xff1a; 列表是一个树状表格&#xff0c;可以无限添加下级&#xff0c;以及对列表的某一行进行增删改查&#xff08;目前查没有写&#xff09;。 原博链接 二、本篇是在原博主的代码基础上添加了部分功能。 功能1&#xff1a; 给树状表格…

ISCSI 1-由零开始

iSCSI的概念 iSCSI&#xff0c;即Internet SCSI&#xff0c;是IETF制订的一项标准&#xff0c;用于将SCSI数据块映射为以太网数据包。从根本上说&#xff0c;它是一种基于IP Storage理论的新型存储技术&#xff0c;该技术将存储行业广泛应用的SCSI接口技术与IP网络技术相结合&a…

存储技术与iSCSI

本章主要介绍基于IP SAN的网络存储iSCSI。iSCSI技术以其低廉的构建成本和优秀的存储性能&#xff0c;博得了很多CIO和存储管理员的喜爱&#xff0c;目前陆续进入企业应用领域&#xff0c;推动了企业的存储环境向集中式转变。虽然&#xff0c;目前对于iSCSI应该在什么样的环境中…