1
krircc 2018-12-05 07:34:55 +08:00 via Android
fhj
|
3
Aruforce 2018-12-05 07:48:54 +08:00 via Android
Synchronized 又不是保证线程调度顺序的,是标识独占的,严格线程的顺序请用 join 方法……至于这样写法对于 count 来说应该不是线程安全的……
|
4
zek 2018-12-05 08:05:57 +08:00 via Android
你可以让线程 2 先睡一会儿就能保证了
|
5
lhx2008 2018-12-05 08:08:54 +08:00 via Android
为啥一个有 static 一个没 static,好玩么。
如果你实现的是 counter,那么你需要定义一个计数+1 的方法,然后设置锁,而不是读写各加一个锁,没有任何意义 |
8
wenb1 OP @lhx2008 这只是一个例子,用来说明 static 和 non-static 的区别。我的问题不是这个要怎样写,而是我不太明白加锁的意义,我的问题大概是加了锁又不能控制线程调度让我得到想要的结果,为什么还要加锁,我可以不同时使用啊
|
9
Aruforce 2018-12-05 08:17:22 +08:00 via Android
@wenb1 实现所谓的线程安全啊……什么样才安全呢?当然是当前资源只有一个线程来使用的状态啊……也就是线程独占……
|
10
lhx2008 2018-12-05 08:20:36 +08:00 via Android
@wenb1 你要是顺序调用就不多线程,不多线程就没必要有锁。而且多线程是同时解决同一个问题,而不是有顺序的解决两个问题,后者应当在一个线程里面执行
|
11
lihongjie0209 2018-12-05 08:22:30 +08:00
|
12
ccpp132 2018-12-05 08:22:41 +08:00
为了防止你 setter 执行到一半的时候执行 getter,你这个例子里本来就没什么鸟用
|
13
vansl 2018-12-05 08:25:34 +08:00 via iPhone 2
建议了解一下互斥与同步的概念。synchronized 只能保证互斥,而你需要的是同步,可以通过设置标志位解决。
|
14
lihongjie0209 2018-12-05 08:25:47 +08:00 1
上面代码的关键部分是:
counter.setCount(Counter.getCount() + 1); set 方法拿到的是一个对象锁, 对于 10 个线程来说, 每一个都是 new 一个对象的, 所以每一个都独占这个对象锁.每一个线程都无须等待就可以直接修改变量, 是线程不安全的. get 方法拿到的是一个类锁, 对于 10 个线程来说, 每一个线程都必须抢占这个锁, 所以 get 是线程安全的. |
15
lhx2008 2018-12-05 08:27:02 +08:00 via Android
@lihongjie0209 然而读写都是原子操作,所以不加锁也是安全的
|
16
lihongjie0209 2018-12-05 08:29:40 +08:00
@lhx2008 错, 读是原子操作, 写是原子操作, 读+写时复合操作, 不保证原子性
|
17
lihongjie0209 2018-12-05 08:30:16 +08:00
@lhx2008 多运行几次代码就会发现最后的结果在 9 和 10 之前摇摆
|
18
azhangbing 2018-12-05 08:31:36 +08:00 via iPhone
饿 你想实现的是生产者和消费者模式吧
|
19
lhx2008 2018-12-05 08:33:20 +08:00 via Android 1
@lihongjie0209 复合操作,不是类提供的,如果是类提供的,要加锁,外部调用是外部调用者的责任,他应该在执行这行代码前后加锁
|
20
lihongjie0209 2018-12-05 08:33:24 +08:00
@vansl 互斥只是一个退化版本的同步
|
23
lhx2008 2018-12-05 08:35:35 +08:00 via Android
@lihongjie0209 不过 9 和 10,这个,明明是这个代码写的太蠢了。。你加不加锁都一样
|
25
wenb1 OP @lihongjie0209 多谢!我对这个例子有了更深的理解!
|
26
lihongjie0209 2018-12-05 08:40:36 +08:00
@lhx2008 废话, 没看到题主说的: 我想问的是在什么样的具体实例里调用这两个方法会导致线程不安全?
|
27
lihongjie0209 2018-12-05 08:52:28 +08:00
@vansl https://gist.github.com/lihongjie0209/26c966b808c03075427d7c72ff34a707 这段代码会一直运行, 哪怕有 volatile 修饰也会有内存可见性问题
|
28
Ico945 2018-12-05 08:53:56 +08:00
锁保证的是共享区(变量)一次只能由一个线程操作,并不能保证线程的执行顺序
|
29
MoHen9 2018-12-05 08:57:11 +08:00 via Android
synchronized 是信号量,状态被放在对象头里面, 我们常说被 static 修饰的方法属于类,内存中有唯一的一个 Class 对象对应着当前类,而这个对象的对象头存放着被 static 修饰的 synchronized 的状态,没有 static 修饰的方法,synchronized 的状态存放在当前对象中。所以,你这是两把锁,想要保证同一个变量的安全。你可以都加 static,或者都不加,或者使用一个单独的对象锁存放 synchronized 的状态。
|
30
araraloren 2018-12-05 08:59:45 +08:00
楼主可以了解一下啥叫互斥,啥叫同步
|
31
sagaxu 2018-12-05 09:01:39 +08:00 via Android 1
@lhx2008 long 类型的写入在某些 arch 下不是原子操作。即使是原子操作,也需要某种同步方式解决内存可见性问题。同一个线程内代码顺序建立 happens-before 关系,不同线程之间要靠同步机制建立。
|
32
wenb1 OP 感谢所有回答我问题的大佬,我继续去学习了!有问题我还会回来的。。。
|
33
azhangbing 2018-12-05 09:33:41 +08:00 1
楼主可以看这个 http://www.iteye.com/topic/806990 这叫线程生产者消费者
|
34
20015jjw 2018-12-05 09:59:34 +08:00 via Android
看中文说这个根本看不懂。。。
|
35
wenb1 OP @azhangbing 你说的很有道理,我去看看,多谢了
|
37
log4geek 2018-12-13 13:56:53 +08:00
|
38
dezhou9 2019-01-05 16:00:33 +08:00 via Android
信号量和读写锁都不如 rcu 性能好
|