线程同步问题

amdgaming 2011-07-01 09:12:03

public class Counter {
private volatile int count = 0;

//若要线程安全执行执行count++,需要加锁
public synchronized void increment() {
count++;
}

public int getCount() {

return count;
}

}

为什么 这种自增 需要 加锁, 我理解为 没有 使用他对象 都有自己的

count , 完全不会影响他 其他 对象啊

除非用 static 的,请 大牛 们 帮忙解释下。。。。谢谢
...全文
444 27 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
27 条回复
切换为时间正序
请发表友善的回复…
发表回复
stalendp 2012-12-24
  • 打赏
  • 举报
回复
引用 22 楼 IamRainLiang 的回复:
在多线程下调用,volatile 是必须的,也是必须加锁的。 1,如果没有 volatile,那么如果线程 A 频繁访问 count,编译器很可能优化其为寄存器,这时线程 B 修改了 count,A 当时是无反应的,此时 A 再修改,B 的修改就被覆盖了。 2,加锁也是必须的,因为两个 CPU 同时对一个地址写,也是可能覆盖情况。 针对这个情况 CPU ……
这个回答很到位。count值用volatile修饰,在多线程中必须的原因,跟Java的内存模型有关(可以参考《Java多线程设计模式详解》一书的附录B Java的内存模型)。具体原因是,每个线程对内存的值都有一个拷贝(也就是线程运行的时候,先要从内存中把相应的值拷贝到工作存储器上),如果没有volatile,或者acychronize等关键词的修饰,各个线程在修改值的时候,就不会保证值的一致性。所以上面的cout用volatile修饰不是应为原子性的问题,而是由于java内存模型决定的。volatile能够保证count在各个线程中的一致性。 内存模型在《Java多线程设计模式详解》一书中有个经典的比喻:主存储器好比是大家看到的黑板;而工作存储器则像是每个人的笔记本。
karl1235 2011-07-05
  • 打赏
  • 举报
回复
楼主的理解的情形是: 多个线程操作多个同一个类的实例,每个线程操作不同的实例,当调用的一个实例方法 操作类变量的时候,需要做同步.
代码的情景是; 多个线程可能操作这个类的一个实例,当每个线程都会调用相同的实例方法的时候,这个方法就需要考虑是否进行同步
wakeUpDoNottLazy 2011-07-05
  • 打赏
  • 举报
回复
[Quote=引用 24 楼 iamrainliang 的回复:]

这里如果优化的话,不用 synchronized
直接 InterlockedIncrement
[/Quote]
InterlockedIncrement ? JAVA 中有?
shanlingge 2011-07-02
  • 打赏
  • 举报
回复
对于是否使用synchronized 或者说要不要加锁,其实没有明确的定义,所谓的线程并发是发生在多个线程竞争同一个资源的时候导致的,如果你对于Counter 每次都new一个新的对象,且变量count又是属于对象内的,就没有必要使用synchronized。因为他们的资源是没有冲突的,但是如果count是另一个类中的资源,那么就有必要进行同步,因为那时这个资源可能是公用的资源。
Rain7758 2011-07-02
  • 打赏
  • 举报
回复
这里如果优化的话,不用 synchronized
直接 InterlockedIncrement
Rain7758 2011-07-02
  • 打赏
  • 举报
回复
另外请各位不要将多线程,和类对象之类的混在一起

从代码来看,互斥就是表明了这个类的对象会被多个线程使用,即
public synchronized void increment() 会被多个线程同时调用
而用锁是不想出现两个线程同时 increment 而结果却只加1的情况
Rain7758 2011-07-02
  • 打赏
  • 举报
回复
在多线程下调用,volatile 是必须的,也是必须加锁的。


1,如果没有 volatile,那么如果线程 A 频繁访问 count,编译器很可能优化其为寄存器,这时线程 B 修改了 count,A 当时是无反应的,此时 A 再修改,B 的修改就被覆盖了。

2,加锁也是必须的,因为两个 CPU 同时对一个地址写,也是可能覆盖情况。
针对这个情况 CPU 提供了互斥指令,这个互斥指令可以阻止另外的 cpu 对某地址进行同时访问,就是“无锁”的根本依赖,即 windows 提供的 interlocked 系列函数
lw_China 2011-07-01
  • 打赏
  • 举报
回复
因为可能有多个线程在同时进行增操作。 不同步的话数据很可能不对。

另外,这代码写得不好,同步操作最好只同步临界资源本身。本例中是count。

否则如果还存在别的同步方法,同时访问两个同步方法时,其中一个会被挂起, 影响性能。
飞跃颠峰 2011-07-01
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 amdgaming 的回复:]
什么情况下 会有 2个线程对 1给对象操作,这个 对象可不是 单态的
有这种可能性吗?
[/Quote]

随便举个例子
假设类A中定义了static Counter c;

在多个线程中都有调用A.c.increment()
amdgaming 2011-07-01
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 chenchenyangll 的回复:]

引用 2 楼 amdgaming 的回复:

那如果成这样,还需要加锁吗?
Java code

public class Counter {
private int count = 0;

//若要线程安全执行执行count++,需要加锁
public synchronized void increment() {
count++;
}

public i……
[/Quote]
什么情况下 会有 2个线程对 1给对象操作,这个 对象可不是 单态的
有这种可能性吗?
飞跃颠峰 2011-07-01
  • 打赏
  • 举报
回复
count++虽然在代码中是看起来“原子级”的操作,但在处理器进行实际运算的时候,由一系列的读取修改写入机器指令完成,因此它不是原子级的,这样多线程并发操作就可能出错,所以在多线程可能同时对一个变量执行这个操作时时必须加上synchronized。
Ps: 在这个场合,给count加上volatile也是不恰当的。

如果你的每个线程都有自己独立的一个Counter对象,那无需加锁。如果多线程共享一个Counter对象,就必须加锁。
chenchenyangll 2011-07-01
  • 打赏
  • 举报
回复
Counter c = new Counter();

// 将c实例赋值给 t1 线程的某个域
// 将c实例赋值给 t2 线程的某个域

线程中 run方法内有调用increment()方法

不锁就会有问题 (++操作不是原子的。 说错了,高手请指出啊= =)
锁了就没问题
Jeelon 2011-07-01
  • 打赏
  • 举报
回复
Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。

在两个或者更多的线程访问的成员变量上使用volatile。当要访问的变量已在synchronized代码块中,或者为常量时,不必使用。

由于使用volatile屏蔽掉了VM中必要的代码优化,所以在效率上比较低,因此一定在必要时才使用此关键字。
stalendp 2011-07-01
  • 打赏
  • 举报
回复
我觉得在这个程序中没有必要加锁,并且volatile都不需要
chenchenyangll 2011-07-01
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 wakeupdonottlazy 的回复:]

package test1;
public class Counter {
private volatile int count = 0;
//若要线程安全执行执行count++,需要加锁
public synchronized void increment() {
count++;
}
public int ge……
[/Quote]

恩 这例子就是我想说的 = =
dong_very_good 2011-07-01
  • 打赏
  • 举报
回复
同意五楼说法
zn85600301 2011-07-01
  • 打赏
  • 举报
回复
allan 2011-07-01
  • 打赏
  • 举报
回复
高人快解答,本人来学习的。。。。。。。。。。。。。。。
chenchenyangll 2011-07-01
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 amdgaming 的回复:]

那如果成这样,还需要加锁吗?
Java code

public class Counter {
private int count = 0;

//若要线程安全执行执行count++,需要加锁
public synchronized void increment() {
count++;
}

public int get……
[/Quote]

如果两个线程都对该实例操作,那么需要加锁
安心逍遥 2011-07-01
  • 打赏
  • 举报
回复
不需要吧
public ServerThread(Vector<ServerThread> threads) {

}

public void run(){

}
加载更多回复(7)

62,635

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧