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

请问各位实现线程安全除了加锁还能有啥别的操作

  •  
  •   qyizhong ·
    qyz777 · 2019-05-28 16:50:57 +08:00 · 5119 次点击
    这是一个创建于 1998 天前的主题,其中的信息可能已经有所发展或是发生改变。

    上周被问到的问题,一下把我问蒙了。问了一下周围的朋友感觉并不是我想要的答案,各位大佬们有好的解答吗

    33 条回复    2019-06-12 14:25:54 +08:00
    sbw
        1
    sbw  
       2019-05-28 16:55:30 +08:00
    无锁队列
    polythene
        2
    polythene  
       2019-05-28 16:56:59 +08:00
    theOneMe
        3
    theOneMe  
       2019-05-28 16:57:32 +08:00
    1:cas;
    2: 变量不可变 例如 final 修饰等等;
    3: ThreadLocal
    mattx
        4
    mattx  
       2019-05-28 16:57:59 +08:00 via iPhone
    用原子变量实现 lock free
    lyy16384
        5
    lyy16384  
       2019-05-28 16:58:32 +08:00
    使用不可变对象
    bxqqq
        6
    bxqqq  
       2019-05-28 17:02:29 +08:00
    锁本来就是一种排队啊,你维护一个队列。
    wr410
        7
    wr410  
       2019-05-28 17:04:07 +08:00
    读的变量不写,写的变量不读。 (误
    gz911122
        8
    gz911122  
       2019-05-28 17:04:22 +08:00
    只用一个线程来处理
    kzfile
        9
    kzfile  
       2019-05-28 17:04:54 +08:00
    不使用多线程
    justfly
        10
    justfly  
       2019-05-28 17:07:14 +08:00
    本质上就是利用 atomic,对应 CPU 的 CMPXCHG。CAS,无锁队列都是在这个基础上实现的。
    raysonx
        11
    raysonx  
       2019-05-28 17:12:06 +08:00 via Android
    1. 只读。
    2. 用原子变量,配合无锁( lock-free )算法。然而编程语言中原子变量的实现在某些平台可能是特定的 CPU 指令( memory barriers ),也有可能还是锁。
    brust
        12
    brust  
       2019-05-28 17:16:26 +08:00
    mq?或者 redis 锁 zk 锁 etcd 锁
    ctrlaltdeletel
        13
    ctrlaltdeletel  
       2019-05-28 17:21:54 +08:00
    个人的想法,不一定正确 /完整…

    - 将线程不安全的操作同步起来(加锁 /使用队列等)
    - 将导致线程不安全的资源封闭起来或去掉( ThreadLocal/只读公共的资源)
    Aresxue
        14
    Aresxue  
       2019-05-28 17:30:44 +08:00
    1.不要跨线程访问共享变量;
    2.使共享变量是 final 类型的;
    3.将共享变量的操作加上同步;
    3.1 java 自身
    3.1.1 锁,包括 synchronied 和 lock
    3.1.2 cas,例如 ConcurrentHashMap
    3.1.3 复制变量,一种用空间换时间的方式,典型的如 ThreadLocal ;
    3.1.4 原子变量,LongAdder 和 Atomic*;
    3.2 中间件,这个太多,缓存比如 redis、zookeeper、数据库()甚至文件都可以做。
    ps:java 自身适用于单机情况,分布式下中间件一般更优。
    russian
        15
    russian  
       2019-05-28 17:33:02 +08:00
    放弃线程使用异步。。。我觉得 cpu 怎么都不可能成为短板把。绝大多数情况还是 io
    mooncakejs
        16
    mooncakejs  
       2019-05-28 17:36:04 +08:00
    CAS, COW
    corvofeng
        17
    corvofeng  
       2019-05-28 18:12:11 +08:00 via Android
    突然想到, 你可以用协程, 这样就不用考虑线程安全了, 考虑进程安全就行了🤣
    lihongjie0209
        18
    lihongjie0209  
       2019-05-28 18:24:27 +08:00   ❤️ 1
    线程安全的本质就是 共享 + 可变
    1. 从不共享的角度来看,

    1.1 单线程无共享, redis
    1.2 多线程, threadLocal, 每个线程都操作自己的数据

    2. 从不可变的角度来看

    2.1 使用不可变的数据结构和对象

    如果使用上述的方法还是解决不了你的问题,那么你就需要一些第三方的服务, 如锁,分布式锁等来保证在某一个具体的时刻, 你的资源只能处于一个状态: 要么共享, 要么可变
    Moker
        19
    Moker  
       2019-05-28 18:25:08 +08:00
    @corvofeng 不同协程一起读一个变量 还是 GG
    ryd994
        20
    ryd994  
       2019-05-28 18:30:07 +08:00 via Android
    @bxqqq 锁可以不保证 FIFO


    @wr410 实际上还是需要原子性。举个例子,如果你的 CPU 写某个 2 字节变量需要 2 个周期,在这两个周期内还是有可能读到错误值的
    从 0x0000 先变成 0x00FF,再变成 0xFFFF,那运气不好就会读到中间值
    这个问题很少遇到是因为一般 64 位 CPU 写 64 位或 32 位整数都是硬件原子的,所以一般没事
    ryd994
        21
    ryd994  
       2019-05-28 18:35:05 +08:00 via Android
    @Moker 不会,线程内部可以保证一致性
    协程不能随便交叉读是因为 Python 或 go 作为高级语言,解释权不保证翻译的原子性。表面上是一行代码,实际上可能被翻译成多个 CPU 指令,中间可能被运行环境打断,穿插其他协程的操作。
    如果你自己手动实现异步操作,那还是可以保证安全的。因为此时就是单线程程序而已。如果连单线程都不能保证安全的话这 CPU 也就废了。
    exonuclease
        22
    exonuclease  
       2019-05-28 20:06:20 +08:00 via iPhone
    cas 原子变量 或者干脆不可变数据
    luozic
        23
    luozic  
       2019-05-28 20:40:24 +08:00 via iPhone
    cas cow copy on write。最经典的 java 里面的 juc Doug lea 大佬的代码
    zpxshl
        24
    zpxshl  
       2019-05-28 22:06:17 +08:00 via Android
    rust。。。
    billlee
        25
    billlee  
       2019-05-28 22:07:53 +08:00
    使用 immutable 数据结构, 函数式编程
    jimages
        26
    jimages  
       2019-05-28 22:13:07 +08:00
    戚总好!
    实现线程安全的办法有:
    1.一种办法是把函数写成无状态的函数,有点类似于函数式编程,这个函数中不使用任何全局变量和静态变量,只使用静态变量。
    2.加锁
    3.使用原子对象
    3.
    slanternsw
        27
    slanternsw  
       2019-05-28 22:31:05 +08:00 via Android
    rust(狗头保命)
    beidounanxizi
        28
    beidounanxizi  
       2019-05-28 23:09:23 +08:00
    看看 go 并发模型 总体来说就两种 共享内存 和 CSP?
    lusi1990
        29
    lusi1990  
       2019-05-29 09:06:11 +08:00 via Android
    只读 是线程安全的,只有一个写是线程安全的,多个写才需要考虑线程安全
    yellbo1
        30
    yellbo1  
       2019-05-29 09:30:03 +08:00
    线程封闭是不是也是线程安全的。。。
    qyizhong
        31
    qyizhong  
    OP
       2019-05-29 09:42:09 +08:00
    谢谢各位,突然知道了好多东西...
    iwtbauh
        32
    iwtbauh  
       2019-05-29 09:59:56 +08:00 via Android
    免锁?除去线程本地变量,就只有免锁算法了,比如

    RCU 读取-拷贝-更新
    免锁队列算法

    等等
    anyele
        33
    anyele  
       2019-06-12 14:25:54 +08:00
    1,CAS
    2,队列
    3,单线程(类似于 redis)
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2698 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 34ms · UTC 15:23 · PVG 23:23 · LAX 07:23 · JFK 10:23
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.