java 多线程
阿神
阿神 2017-04-17 17:57:27
[Java讨论组]

以下代码高并发时会有啥问题,怎么优化

阿神
阿神

闭关修行中......

全部回复(7)
PHP中文网

1、用了synchronized修饰了方法,又用synchronized修饰方法体,这两者是等效的,都是获得this(MyStack)的对象监视器并且临界区也是一致的,同是因为synchronized是可重入的,所以你这样用不会发生错误,但是这是不必要的;

2、可能会发生 @房管局规划部 中出现的错误,wait()可能出现假唤醒,而不满足临界条件,后续逻辑就会异常。
可以参看jdk wait()方法的注释描述:

所以,应该是这样:

synchronized( method_or_shared_object){
    while(list.size()<=0)
        wait();
    // pop something...
}

一般来说,都需要在while(condition) wait()来防止假唤醒。

巴扎黑

这段代码在高并发的情况下会出现锁竞争激烈,性能低下的问题。其它的死锁什么的不会出现,不要想太多了。高并发场景建议用concurrent linked queue,分段加锁,能降低锁竞争

阿神

实际运行了一下代码,会报错

notify:Thread-0
Thread-99-pop:aaaa
--------------------
Exception in thread "Thread-0" java.lang.ArrayIndexOutOfBoundsException: -1
    at java.util.ArrayList.elementData(Unknown Source)
    at java.util.ArrayList.remove(Unknown Source)
    at MyStack.pop(MyStack.java:21)
    at MyStack$1.run(MyStack.java:34)

调用代码如下

public static void main(String[] args) throws IOException {
        
        final MyStack test = new MyStack();
        for (int i = 0; i < 100; i++) {
            Thread t = new Thread() {
                @Override
                public void run() {
                    super.run();
                    try {
                        String str = test.pop();
                        System.err.println("pop:" + str);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
            t.start();
        }
        test.push("aaaa");
}

当第99个线程进入的时候,此时并没有进入wait,而直接取走了数据
此时notify启动了第一个线程Thread-0,然后就就越界了。。。

PHP中文网

最好用线程池

高洛峰

synchronized使用有问题,在方法头部定义使用了,就没必要在方法体内再次使用,属于可重入锁,无任何意义。

黄舟

list变量每个线程进来都会new一个新的吧

天蓬老师

首先synchronized修饰方法的问题

  • 对于非static方法,其作用相当于synchronized(this):
    synchronized void method(){

       // method body

    }
    // 等价于
    void method() {

       synchronized(this){
           // method body
       }

    }

  • 对于static方法,其相当于synchronized(YourClass.class):
    class YourClass {

       synchronized static void method() {
           // method body
       }
       // 等价于
       static void method() {
           synchronized(YourClass.class) {
               // method body
           }
       }

    }

其次关于假唤醒问题,就是@spance说的。官方docde描述是:

A thread can also wake up without being notified, interrupted, or timing out, a so-called spurious wakeup.

官方给出的解决方案是:

synchronized (obj) {
     while (<condition does not hold>)
         obj.wait();
     ... // Perform action appropriate to condition
  }

The doc

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号