V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
skywayman
V2EX  ›  程序员

JDK 原罪...

  •  
  •   skywayman · 2017-02-23 16:56:14 +08:00 · 6317 次点击
    这是一个创建于 2823 天前的主题,其中的信息可能已经有所发展或是发生改变。

    多线程开发是 Java 语言中经常用到的(别说你不用)....

    当我们谈论多线程的时候总有一个讨论点 : 线程安全. 当我们谈论线程安全的时候我们在谈什么? 什么原子性\可见性\顺序性\锁\同步\CAS\xx 原则\volatile 语法\jdk 的新库\vector 与 arraylist 哪个安全\面试考题等等等等....

    SO...

    妈蛋,能不能先把 JDK 中成百上千个类中,哪些不是线程安全的给苦逼的程序员标注出来先? 原罪啊... 老司机都表示不淡定了...

    第 1 条附言  ·  2017-02-23 23:50:59 +08:00
    补弃一下,有些 v2exer 没理解:
    本意并不是说 Java 的多线程机制设计的不好,反而是设计的有些让人感动. 当然也如人所说是在下能力不够,没有把上千个基础 java 类中哪些不是线程安全的给找出来并记住;

    真正想表达的意思只有一个: JDK 开发者肯定知道原始类库哪些不是线程安全的对吗?那在引入多线程的时候,为什么不在(预)编译的时候识别多线程环境,把不安全的基础类使用给警告出来,非得各种躺坑后把结果和过程称之为"开发经验"或"血泪教训"?
    48 条回复    2017-02-25 17:54:01 +08:00
    enenaaa
        1
    enenaaa  
       2017-02-23 17:11:30 +08:00
    把你不确认的都当成非线程安全
    skywayman
        2
    skywayman  
    OP
       2017-02-23 17:16:48 +08:00
    @enenaaa 新一茬韭菜得接着采坑不是....
    linbiaye
        3
    linbiaye  
       2017-02-23 17:17:19 +08:00
    线程安全的不都给你放 java.util.concurrent 下面了么。
    skywayman
        4
    skywayman  
    OP
       2017-02-23 17:35:59 +08:00
    @linbiaye 话是没有错,但你要用 SimpleDateFormat,用 StringBuilder 嘛...
    kappa
        5
    kappa  
       2017-02-23 18:02:37 +08:00
    @skywayman RTFM

    Synchronization

    Date formats are not synchronized. It is recommended to create separate format instances for each thread. If multiple threads access a format concurrently, it must be synchronized externally.

    或者继续当韭菜,也方便筛人
    mokeyjay
        6
    mokeyjay  
       2017-02-23 18:28:37 +08:00 via Android
    问:程序猿为何要使用多线程?
    答:因为他们觉得生活还不够乱
    xuyankang
        7
    xuyankang  
       2017-02-23 18:31:36 +08:00
    线程不安全的类也能线程安全,线程安全的类也能线程不安全。。。
    hepin1989
        8
    hepin1989  
       2017-02-23 19:54:44 +08:00
    能力问题
    kaneg
        9
    kaneg  
       2017-02-23 19:58:39 +08:00 via iPhone
    Java 的多线程设计是相当优雅的,觉得不安全就加 synchronized ,没有那么可怕。
    ihuotui
        10
    ihuotui  
       2017-02-23 21:08:57 +08:00 via iPhone
    因为场景太多,只是你见识少,例如在多线程下同一个 id 的操作线程要求顺序,使用 lock 的公平锁。
    ovear
        11
    ovear  
       2017-02-23 21:11:16 +08:00
    那啥。。要怕的话可以直接加一个 synchronize
    出了效率问题,或者有时间再弄。。
    Sight4
        12
    Sight4  
       2017-02-23 21:29:15 +08:00
    线程安全这个问题不是 Java 独有的吧....
    tianice
        13
    tianice  
       2017-02-23 21:56:12 +08:00
    jdk 有很多问题,基本都是要兼容旧版本导致的,早就该改改了
    hjc4869
        14
    hjc4869  
       2017-02-23 21:58:14 +08:00
    原则上文档 /标准中没有说线程安全就代表实现时没必要保证线程安全,也就是你不能当线程安全的用。
    gouchaoer
        15
    gouchaoer  
       2017-02-23 22:11:41 +08:00 via Android
    java 的多线程做的很好了,你居然还不满足
    gam2046
        16
    gam2046  
       2017-02-23 22:18:04 +08:00
    Windows 原罪.....

    装软件是 Windows 中经常用到的(别说你不用)....


    当我们谈论装软件的时候总有一个讨论点 : 有没有病毒. 当我们谈论病毒的时候我们在谈什么? 什么 360\杀毒软件\主动防御\HIPS\安全管家\安全助手等等等等....

    SO...

    妈蛋,能不能先把 Windows 中成千上万的软件中,哪些没有病毒的给苦逼的用户标注出来先? 原罪啊... 老司机都表示不淡定了...
    icebergSnow
        17
    icebergSnow  
       2017-02-23 22:26:11 +08:00 via Android
    不太懂你,病毒又不是微软产的
    skywayman
        18
    skywayman  
    OP
       2017-02-23 23:37:35 +08:00
    @gam2046 亏你打这么多,本质没理解. JDK 是原生的,直接给开发人员使用的,病毒是 windows 中原生的嘛? 明明是第三方编写并传播的,要反思的是 windows 的内部机理吧...
    @gouchaoer 不是不满足,只是不明白既然引入了多线程,为什么不把基础类库做的更好一点,比如编译的时候能识别某基础类库在多线程环境下会有问题,出现个警告之类的....而不用人去"趟坑",然后把结果和过程称之为"开发经验"或"血泪教训";
    @hjc4869 基础类库是不是太多了点,我反正没有全部看完
    @tianice 知音
    @Sight4 我并不是抱怨线程安全问题
    @hepin1989 我水平一般
    @xuyankang 这是实话
    @kappa 其实只是不明白既然引入了多线程,为什么不把基础类库做的更好一点,比如编译的时候能识别某类库在多线程环境下会有问题,出现个警告之类的....而不用人去"趟坑",然后把结果和过程称之为"开发经验"或"血泪教训";
    skywayman
        19
    skywayman  
    OP
       2017-02-23 23:39:26 +08:00
    @ihuotui 只能说还完全没懂我意思
    Allianzcortex
        20
    Allianzcortex  
       2017-02-23 23:52:57 +08:00 via iPhone
    joda-time 和 stringbuffer
    mikulch
        21
    mikulch  
       2017-02-24 00:02:25 +08:00
    楼主之前写啥语言的。
    ovear
        22
    ovear  
       2017-02-24 00:06:11 +08:00
    @skywayman
    线程安全是跟程序员的设计有关
    并不是说类库在多线程情况下就一定有问题。而是可能出现意料外的情况,但是在正确的设计中,即使是多线程环境,一些所谓的非线程安全的类库也不会产生 意料外 的情况。而这时候编译器抛出 warning 就有点。。。了

    所以这个属于业务逻辑问题,锅在程序员,跟编译器关系不大。
    skywayman
        23
    skywayman  
    OP
       2017-02-24 00:15:48 +08:00
    @ovear 那什么是正确的设计?把线程安全的方方面面都全部搞懂后设计出来的程序就是正确的设计了?很多业务复杂的多线程环境,基础类库经常出现隐性的深层次问题,调起来非常的伤神.这个不否认吧. 我觉得出 warning 多好,即能淘汰旧 api,也能迫使开发人员知识体系升级,还减少出错,一举多得!
    ovear
        24
    ovear  
       2017-02-24 00:24:04 +08:00
    @skywayman 所以你也说了,这是“你觉得”

    同步不是百利而无一害的,它是有代价的,这是由程序员自己决定的,是否使用读同步,写同步。这些都是有代价的。
    打个比方,在外部条件的约束下,也许是多线程中使用非线程安全的类库,但是却能保证不出问题

    再打个比方,一个数据结构中,多个线程共用,但是每个线程负责不同的部分。此时有使用读写同步的必要么。

    诸如此类的情况太多了,这应该是程序员去关心的业务具体展示,而不是编译器关心你的算法
    ovear
        25
    ovear  
       2017-02-24 00:28:38 +08:00   ❤️ 1
    @ovear 而且更重要的是,所谓官方的线程安全,很可能跟你业务所需要的线程安全,是有差异的。类库的线程安全是不能实现你需要的效果的。
    最简单的比方

    public static void main(String[] args){
    while(true){
    for(int i = 0; i<10; i++){
    vector.add(i);
    }
    }

    //一个线程删数据
    Thread removeThread = new Thread(new Runnable(){
    @Override
    public void run(){
    for(int i=0 ; i<vector.size() ;i++){
    vector.remove(i);
    }
    }
    });

    //一个线程读数据
    Thread printThread = new Thread(new Runnable() {
    @Override
    public void run(){
    for(int i=0 ; i<vector.size() ;i++){
    System.out.println(vector.get(i));
    }
    }
    });

    removeThread.start();
    printThread.start();

    //防止过多线程,内存溢出
    while(Thread.activeCount() > 20);
    }


    上述代码就会产生意料外的情况,那么 Vector 是非线程安全的么?


    代码来自: https://zhuanlan.zhihu.com/p/21339889
    zhuangzhuang1988
        26
    zhuangzhuang1988  
       2017-02-24 00:58:08 +08:00
    题主想法是好的
    在 《 Java 并发编程实战》这本书中就大量使用了这个方法使用的是标注,附录中也有详细描述
    bombless
        27
    bombless  
       2017-02-24 02:06:23 +08:00 via Android
    经常是这样的:除非特别说明,都是线程不安全的。
    来我们 rust 吧,仍然是除非特别说明都是线程不安全的。不过我们的线程安全在类型中被标出来了,因此编译器会检查一些情况,比如数据竞争。
    des
        28
    des  
       2017-02-24 07:54:08 +08:00 via Android
    @bombless 主要还是怕踩坑。好的设计当然是不用说的。
    打比方来说 c 里面有个根据 DNS 获取 ip 的 API ,就有线程不安全版的,如果没有标注的话,就直接掉进去了,总不能所有东西都加锁吧?
    Citrus
        29
    Citrus  
       2017-02-24 08:02:48 +08:00 via iPhone
    Citrus
        30
    Citrus  
       2017-02-24 08:04:55 +08:00 via iPhone
    @ovear 虽然你说的没错,但是感觉你有点曲解了楼主的意思ˊ_>ˋ感觉楼主只是想方便快捷的知道哪些是线程安全的哪些不是而已,这样就不用用个啥就提心吊胆的吧~
    ob
        31
    ob  
       2017-02-24 08:30:03 +08:00 via Android
    @Citrus 用的时候,每个类的注释是有写的吧。
    zacard
        32
    zacard  
       2017-02-24 09:16:25 +08:00
    在多线程环境中,非线程安全的类不一定就有问题啊。。。。
    ovear
        33
    ovear  
       2017-02-24 09:50:54 +08:00
    @Citrus 自动完成以及提示
    比如说 NetBeans 可以按住 ctrl 和类的名字看当前类的注释,一般线程安全和非线程安全都是用粗体字标记,应该已经够简单了吧=。=

    我只是认为,这个操作不应该由编译器进行 warning
    pangliang
        34
    pangliang  
       2017-02-24 10:18:16 +08:00
    楼主应该去写 rust
    m8syYID5eaas8hF7
        35
    m8syYID5eaas8hF7  
       2017-02-24 10:25:35 +08:00
    只能慢慢适应。其实看一下源代码很快就可以判断是不是线程安全的嘛
    skywayman
        36
    skywayman  
    OP
       2017-02-24 10:43:13 +08:00
    @Citrus 言简意赅,知音,哈哈
    @ovear 示例没毛病,@Citrus 表达了我的意思,假如我是一个小白,先不管业务逻辑,代码中不是用的 vector,是用的 arraylist,如果编译器出警告说:在多线程环境中用 arraylist 不安全,建议切换 vector,同理 Integer 建议切换成 AtomicInteger 是否会更好?
    @des 知音,哈哈.
    @pangliang 有空了解一下.谢谢!
    zhzy0077
        37
    zhzy0077  
       2017-02-24 10:55:27 +08:00 via Android
    可是编译器怎么知道你这个 ArrayList 会不会用在多线程环境中。。如果就用 ArrayList 存数据,不去修改的话,事实上这个 ArrayList 也是线程安全的,编译器也要告警应该用 Vector ?
    jaxonHu
        38
    jaxonHu  
       2017-02-24 10:59:29 +08:00
    《多处理器编程的艺术》
    sagaxu
        39
    sagaxu  
       2017-02-24 11:20:12 +08:00
    没写安全的,就是不安全的,即时某个版本实现的安全,也可能随时改变。
    WhoMercy
        40
    WhoMercy  
       2017-02-24 11:43:02 +08:00
    Junior Coder :这什么辣鸡编译器(IDE),怎么不把所有老司机约定成俗的东西都提示出来(我又不是老司机),使用的时候又不想看文档,也从不看源码,你不提示我怎么知道,是不是看我掉坑里很开心??
    这辣鸡*DK ,你只要告诉我怎么用就好了嘛,最好再带上几个不同版本的业务示例。

    开心就好
    youxiachai
        41
    youxiachai  
       2017-02-24 11:54:55 +08:00
    lz 还是太懒了...

    当年..我学 java 的时候....一个月(闲时)把所有类包看完....
    skywayman
        42
    skywayman  
    OP
       2017-02-24 12:33:03 +08:00
    @WhoMercy :) 可能开源就是这德行吧...
    @youxiachai 皇上,还记得当年湖畔的夏雨荷 JPEGHuffmanTable 是不是安全的?
    @zhzy0077 =和==都知道,何况 thread 和 runnable 上下文环境,编译器肯定有办法,再者换成 vector 也不是错啊,哪天业务变更,说不定 vector 更安全不是?
    xianyu0
        43
    xianyu0  
       2017-02-24 12:51:12 +08:00
    关 JDK 什么事,这是 JVM 的事吧
    zhzy0077
        44
    zhzy0077  
       2017-02-24 13:01:06 +08:00 via Android
    1. 要是编译器这个都知道,就能帮你在可能发生 race condition 的地方自动加锁了,显然是不可能的。
    2. 那按照你的说法, JDK 不用 ArrayList 了?大家一起用 Vector ?
    AntiGameZ
        45
    AntiGameZ  
       2017-02-24 13:09:51 +08:00
    @WhoMercy IDE 就应该尽最大可能去辅助程序员,这没有什么不对。如果能够有办法让人不看文档不搜索就很容易的根据 context 给出提示/警告/报错,不正应该是工具要去做的事情么?

    觉得 LZ 说的有理,那么多冷嘲热讽偏离主题的...
    xmh51
        46
    xmh51  
       2017-02-24 13:15:02 +08:00
    ide 真达到这种底部,还要程序员干啥?
    sheep3
        47
    sheep3  
       2017-02-24 14:50:26 +08:00
    单纯的能力问题,你觉得要怎么告诉你哪些安全哪些不安全才行? doc 上面写着够不够?
    Khlieb
        48
    Khlieb  
       2017-02-25 17:54:01 +08:00 via Android
    Java 有两大开发工具,一个叫 JDK ,一个叫 OpenJDK
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2587 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 15:47 · PVG 23:47 · LAX 07:47 · JFK 10:47
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.