加入收藏 | 设为首页 | 会员中心 | 我要投稿 我爱制作网_潮州站长网 (http://www.0768zz.com/)- 物联安全、建站、操作系统、云计算、数据迁移!
当前位置: 首页 > 教程 > 正文

Java多线程:一道阿里面试题的分析与克服

发布时间:2021-12-11 15:48:53 所属栏目:教程 来源:互联网
导读:引言: 通过多线程的面试题目分析,来深入理解Java线程的状态转变过程。 最近在学习Java多线程设计的时候,在网上看到一个面试题目的讨论,虽然楼主所说有些道理,但感觉还是有些问题,故此在和同事讨论以后还是有了若干收获,在此略作总结。 首先,来看看这

引言: 通过多线程的面试题目分析,来深入理解Java线程的状态转变过程。
 
最近在学习Java多线程设计的时候,在网上看到一个面试题目的讨论,虽然楼主所说有些道理,但感觉还是有些问题,故此在和同事讨论以后还是有了若干收获,在此略作总结。
 
首先,来看看这个面试题目吧。
 
    public class MyStack {
        private List<String> list = new ArrayList<String>();
     
        public synchronized void push(String value) {
            synchronized (this) {
                list.add(value);
                notify();
            }
        }
     
        public synchronized String pop() throws InterruptedException {
            synchronized (this) {
                if (list.size() <= 0) {
                    wait();
                }
                return list.remove(list.size() - 1);
            }
        }
    }
 
问题:  这段代码大多数情况下运行正常,但是某些情况下会出问题。什么时候会出现什么问题?如何修正?
 
代码分析:
 
从整体上,在并发状态下,push和pop都使用了synchronized的锁,来实现同步,同步的数据对象是基于List的数据;大部分情况下是可以正常工作的。
 
问题描述:
 
状况1:
 
1.  假设有三个线程: A,B,C.  A 负责放入数据到list,就是调用push操作, B,C分别执行Pop操作,移除数据。
 
2.  首先B先执行,于pop中的wait()方法处,进入waiting状态,进入等待队列,释放锁。
 
3.  A首先执行放入数据push操作到List,在调用notify()之前; 同时C执行pop(),由于synchronized,被阻塞,进入Blocked状态,放入基于锁的等待队列。注意,这里的队列和2中的waiting等待队列是两个不同的队列。
 
4.    A线程调用notify(),唤醒等待中的线程A。
 
5.    如果此时, C获取到基于对象的锁,则优先执行,执行pop方法,获取数据,从list移除一个元素。
 
6.  然后,A获取到竞争锁,A中调用list.remove(list.size() - 1),则会报数据越界exception。
 
状况2:
 
1.  相同于状况1
 
2.  B、C都处于等待waiting状态,释放锁。等待notify()、notifyAll()操作的唤醒。
 
3.  存在被虚假唤醒的可能。
 
何为虚假唤醒?
 
虚假唤醒就是一些obj.wait()会在除了obj.notify()和obj.notifyAll()的其他情况被唤醒,而此时是不应该唤醒的。
 
解决的办法是基于while来反复判断进入正常操作的临界条件是否满足:
 
    synchronized (obj) {
            while (<condition does not hold>)
                obj.wait();
            ... // Perform action appropriate to condition
        }
 
如何修复问题?
 
#1.  使用可同步的数据结构来存放数据,比如LinkedBlockingQueue之类。由这些同步的数据结构来完成繁琐的同步操作。
 
#2.  双层的synchronized使用没有意义,保留外层即可。
 
#3.  将if替换为while,解决虚假唤醒的问题。

(编辑:我爱制作网_潮州站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读