public class Counter {
private volatile int count = 0; //若要线程安全执行执行count++,需要加锁
public synchronized void increment() {
count++;
} public int getCount() { return count;
}}为什么 这种自增 需要 加锁, 我理解为 没有 使用他对象 都有自己的 count , 完全不会影响他 其他 对象啊除非用 static 的,请 大牛 们 帮忙解释下。谢谢

解决方案 »

  1.   

    问题大概出在volatile身上?我不懂。
      

  2.   

    那如果成这样,还需要加锁吗?public class Counter {
        private int    count    = 0;    //若要线程安全执行执行count++,需要加锁
        public synchronized void increment() {
            count++;
        }    public int getCount() {        return count;
        }}
      

  3.   

    不需要吧
    public ServerThread(Vector<ServerThread> threads) {

    } public void run(){}
      

  4.   

    看看这个 http://zhidao.baidu.com/question/20231700.html
      

  5.   

    我觉得在这个程序中没有必要加锁,并且volatile都不需要
      

  6.   

    Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。在两个或者更多的线程访问的成员变量上使用volatile。当要访问的变量已在synchronized代码块中,或者为常量时,不必使用。由于使用volatile屏蔽掉了VM中必要的代码优化,所以在效率上比较低,因此一定在必要时才使用此关键字。
      

  7.   

    Counter c = new Counter();// 将c实例赋值给 t1 线程的某个域
    // 将c实例赋值给 t2 线程的某个域线程中 run方法内有调用increment()方法不锁就会有问题  (++操作不是原子的。 说错了,高手请指出啊= =)
    锁了就没问题
      

  8.   

    count++虽然在代码中是看起来“原子级”的操作,但在处理器进行实际运算的时候,由一系列的读取修改写入机器指令完成,因此它不是原子级的,这样多线程并发操作就可能出错,所以在多线程可能同时对一个变量执行这个操作时时必须加上synchronized。
    Ps: 在这个场合,给count加上volatile也是不恰当的。如果你的每个线程都有自己独立的一个Counter对象,那无需加锁。如果多线程共享一个Counter对象,就必须加锁。
      

  9.   


    随便举个例子
    假设类A中定义了static Counter c;在多个线程中都有调用A.c.increment()
      

  10.   

    因为可能有多个线程在同时进行增操作。 不同步的话数据很可能不对。另外,这代码写得不好,同步操作最好只同步临界资源本身。本例中是count。否则如果还存在别的同步方法,同时访问两个同步方法时,其中一个会被挂起, 影响性能。
      

  11.   


    随便怎样都有可能啊工作线程需要一个Counter类实例作为他的成员,
    那么线程需要调用某个方法将这个实例赋值给他的成员吧~这样就可能两个线程公用一个Counter实例当然,可能你的Counter类并不是这个用法,但的确是存在不加锁会出问题的可能具体还是看这个类的职责是什么,有无线程同步的需求如果这个类根本不可能被多线程使用,那么就不需要加锁
      

  12.   

    package test1;
    public class Counter {
        private volatile int    count    = 0;
        //若要线程安全执行执行count++,需要加锁
        public synchronized void increment() {
            count++;
        }
        public int getCount() {
            return count;
        }
    }class MyTask implements Runnable{
    private Counter counter;
    public MyTask(Counter counter) {
    this.counter = counter;
    }
    public void run() {
    counter.increment();
    }
    }class Concurrent{
    public static void main(String[] args) {
    /*
     * thread1 和 thread2 同时对一个 counter 进行操作。这种情况下,counter 需要注意线程安全问题
     */
    Counter counter = new Counter();
    Thread thread1 = new Thread(new MyTask(counter));
    thread1.start();
    Thread thread2 = new Thread(new MyTask(counter));
    thread2.start();

    }
    }
      

  13.   

    就是若该对象可能被多个线程使用的话那就需要加锁了,
    反之就不需要,甚至连volatile都可以省了……
      

  14.   

    对于是否使用synchronized 或者说要不要加锁,其实没有明确的定义,所谓的线程并发是发生在多个线程竞争同一个资源的时候导致的,如果你对于Counter 每次都new一个新的对象,且变量count又是属于对象内的,就没有必要使用synchronized。因为他们的资源是没有冲突的,但是如果count是另一个类中的资源,那么就有必要进行同步,因为那时这个资源可能是公用的资源。
      

  15.   

    在多线程下调用,volatile 是必须的,也是必须加锁的。
    1,如果没有 volatile,那么如果线程 A 频繁访问 count,编译器很可能优化其为寄存器,这时线程 B 修改了 count,A 当时是无反应的,此时 A 再修改,B 的修改就被覆盖了。2,加锁也是必须的,因为两个 CPU 同时对一个地址写,也是可能覆盖情况。
    针对这个情况 CPU 提供了互斥指令,这个互斥指令可以阻止另外的 cpu 对某地址进行同时访问,就是“无锁”的根本依赖,即 windows 提供的 interlocked 系列函数
      

  16.   

    另外请各位不要将多线程,和类对象之类的混在一起从代码来看,互斥就是表明了这个类的对象会被多个线程使用,即
     public synchronized void increment() 会被多个线程同时调用
    而用锁是不想出现两个线程同时 increment 而结果却只加1的情况
      

  17.   

    这里如果优化的话,不用 synchronized 
    直接 InterlockedIncrement
      

  18.   

    InterlockedIncrement ? JAVA 中有?
      

  19.   


    这个回答很到位。count值用volatile修饰,在多线程中必须的原因,跟Java的内存模型有关(可以参考《Java多线程设计模式详解》一书的附录B Java的内存模型)。具体原因是,每个线程对内存的值都有一个拷贝(也就是线程运行的时候,先要从内存中把相应的值拷贝到工作存储器上),如果没有volatile,或者acychronize等关键词的修饰,各个线程在修改值的时候,就不会保证值的一致性。所以上面的cout用volatile修饰不是应为原子性的问题,而是由于java内存模型决定的。volatile能够保证count在各个线程中的一致性。
    内存模型在《Java多线程设计模式详解》一书中有个经典的比喻:主存储器好比是大家看到的黑板;而工作存储器则像是每个人的笔记本。