Java 多线程 synchoronized 关键字问题

2018-12-05 07:08:17 +08:00
 wenb1
刚开始学多线程,今天在网上看到了下面这个例子,给出的解释是 static 的锁是在 Counter.class 里,非 static 的锁是在 this object 里,它们两个可以同时使用,所以会导致线程不安全。我想问的是在什么样的具体实例里调用这两个方法会导致线程不安全,比如我有线程 1 和线程 2,我想让线程 1 调用 setter,然后线程 2 再调用 getter。在这种情况下,就算都上 static synchoronized 锁,我也不能保证调度器一定先调用线程 1,再调用线程 2 啊?跟不上锁有什么区别?我可以都不上锁,然后调用线程 1 执行 setter,再调用线程 2 执行 getter。

求大佬们指点!!多谢了!

代码如下:

public class Counter{

private static int count = 0;

public static synchronized int getCount(){
return count;
}

public synchoronized setCount(int count){
this.count = count;
}

}

原文 link: https://javarevisited.blogspot.com/2011/04/synchronization-in-java-synchronized.html
3772 次点击
所在节点    Java
38 条回复
krircc
2018-12-05 07:34:55 +08:00
fhj
wenb1
2018-12-05 07:41:41 +08:00
@krircc 什么意思?
Aruforce
2018-12-05 07:48:54 +08:00
Synchronized 又不是保证线程调度顺序的,是标识独占的,严格线程的顺序请用 join 方法……至于这样写法对于 count 来说应该不是线程安全的……
zek
2018-12-05 08:05:57 +08:00
你可以让线程 2 先睡一会儿就能保证了
lhx2008
2018-12-05 08:08:54 +08:00
为啥一个有 static 一个没 static,好玩么。
如果你实现的是 counter,那么你需要定义一个计数+1 的方法,然后设置锁,而不是读写各加一个锁,没有任何意义
wenb1
2018-12-05 08:09:56 +08:00
@Aruforce 那为什么还需要 Synchronized 呢?
wenb1
2018-12-05 08:10:22 +08:00
@zek 那效率不就低了
wenb1
2018-12-05 08:15:13 +08:00
@lhx2008 这只是一个例子,用来说明 static 和 non-static 的区别。我的问题不是这个要怎样写,而是我不太明白加锁的意义,我的问题大概是加了锁又不能控制线程调度让我得到想要的结果,为什么还要加锁,我可以不同时使用啊
Aruforce
2018-12-05 08:17:22 +08:00
@wenb1 实现所谓的线程安全啊……什么样才安全呢?当然是当前资源只有一个线程来使用的状态啊……也就是线程独占……
lhx2008
2018-12-05 08:20:36 +08:00
@wenb1 你要是顺序调用就不多线程,不多线程就没必要有锁。而且多线程是同时解决同一个问题,而不是有顺序的解决两个问题,后者应当在一个线程里面执行
lihongjie0209
2018-12-05 08:22:30 +08:00
ccpp132
2018-12-05 08:22:41 +08:00
为了防止你 setter 执行到一半的时候执行 getter,你这个例子里本来就没什么鸟用
vansl
2018-12-05 08:25:34 +08:00
建议了解一下互斥与同步的概念。synchronized 只能保证互斥,而你需要的是同步,可以通过设置标志位解决。
lihongjie0209
2018-12-05 08:25:47 +08:00
上面代码的关键部分是:

counter.setCount(Counter.getCount() + 1);



set 方法拿到的是一个对象锁, 对于 10 个线程来说, 每一个都是 new 一个对象的, 所以每一个都独占这个对象锁.每一个线程都无须等待就可以直接修改变量, 是线程不安全的.

get 方法拿到的是一个类锁, 对于 10 个线程来说, 每一个线程都必须抢占这个锁, 所以 get 是线程安全的.
lhx2008
2018-12-05 08:27:02 +08:00
@lihongjie0209 然而读写都是原子操作,所以不加锁也是安全的
lihongjie0209
2018-12-05 08:29:40 +08:00
@lhx2008 错, 读是原子操作, 写是原子操作, 读+写时复合操作, 不保证原子性
lihongjie0209
2018-12-05 08:30:16 +08:00
@lhx2008 多运行几次代码就会发现最后的结果在 9 和 10 之前摇摆
azhangbing
2018-12-05 08:31:36 +08:00
饿 你想实现的是生产者和消费者模式吧
lhx2008
2018-12-05 08:33:20 +08:00
@lihongjie0209 复合操作,不是类提供的,如果是类提供的,要加锁,外部调用是外部调用者的责任,他应该在执行这行代码前后加锁
lihongjie0209
2018-12-05 08:33:24 +08:00
@vansl 互斥只是一个退化版本的同步

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/514393

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX