iteye_7931 2011-11-03 10:37
浏览 228
已采纳

关于线程同步synchronized的一个基础问题

代码如下:
class Counter {
private static int count;

//Object lock = new Object();

public  int getCount() {
    synchronized(Counter.class){
        return count++;
    }

// synchronized(lock){
// return count++;
// }

}

}

这个类用来生成序列号,测试发现:
如果在 getCount方法上面用同步 public [color=red]synchronized[/color] int getCount() {...}当并发调用线程很多时,返回的序列号仍然会有重复。
如果自定义一个对象,在这个对象上应用同步,也会出现序列号重复问题。
只有对 Counter.class 加锁才能够达到预期的效果。

这三种方式有啥区别,线程的那些书上面的例子不都是在方法上面直接用同步么?请各位帮忙解答。

  • 写回答

5条回答 默认 最新

  • mingyang2013 2011-11-04 23:34
    关注

    楼主,我完全理解你的意思!你一定看楼上的回复看得晕了吧?那么,我会以简单易懂的语言来回答这个问题,请往下看:

    1、你总共用了三种加锁的方法:
    (1)
    [code="java"]
    public int getCount() {
    synchronized(Counter.class){
    return count++;
    }
    [/code]
    (2)
    [code="java"]synchronized(lock){
    return count++;
    } [/code]
    (3)
    [code="java"]public synchronized int getCount() {...}[/code]

    2、其实,你的第(3)种方法和如下方式是等同的:
    [code="java"]
    public int getCount() {
    synchronized(this){
    return count++;
    }
    [/code]

    3、那么,你需要明白java的加锁机制是怎样的。即,多个线程执行一段代码,只有拿到这段代码的锁之后才能执行,其他线程如果拿不到这个“锁”则只能等待,这叫做“互斥”。而要确保线程与线程之间的互斥,只有当他们去拿锁时,那个锁是同一个对象!(这点理解到很重要,是同一对象!)。

    4、好了,看了上面我的说明,这下你能明白错误发生原因了。
    A. 在你的第(1)种加锁方式中,用的是Counter.class,这是类的元对象,在整个虚拟机运行过程中可以认为是唯一的,他是在类被加载的时候创建的(这个稍微扯得有点远,你明白他是唯一的一个对象就ok了),所以不同线程执行里面的代码时,它们是去拿的同一把锁,也就能保证互斥了。
    B. 方式(2)加锁中,很明显,不同线程中,你会new不同的Counter,那么,作为“锁”的对象lock也就不是同一个,也就无法保证互斥。
    C. 方式(3)相信你应该能理解了吧,你在不同线程中用new的不同Counter调用方法,this肯定也就不同了。

    5、ok,希望你看懂了我的说明,我可是手敲的这么字啊。呵呵,如有不懂之处,可以给我私信哈。我当时学多线程时也是相当痛苦,不过理解了就发现也不是那么痛苦了。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(4条)

报告相同问题?

悬赏问题

  • ¥15 maple软件,用solve求反函数出现rootof,怎么办?
  • ¥50 汇编语言除法溢出问题
  • ¥65 C++实现删除N个数据列表共有的元素
  • ¥15 Visual Studio问题
  • ¥15 state显示变量是字符串形式,但是仍然红色,无法引用,并显示类型不匹配
  • ¥20 求一个html代码,有偿
  • ¥100 关于使用MATLAB中copularnd函数的问题
  • ¥20 在虚拟机的pycharm上
  • ¥15 jupyterthemes 设置完毕后没有效果
  • ¥15 matlab图像高斯低通滤波