synchronized关键字的作用范围

昨日终于对synchronized这个关键字有了更进一步的理解,记录一下,方便日后查询。

假设我有一个这样的类:

class MultiThreadTest implements Runnable {

    int myId;

    public MultiThreadTest() {
        myId = 0;
    }

    public MultiThreadTest(int id) {
        myId = id;
    }

    @Override
    public synchronized void run() {
        if (myId == -1) {           //如果没有赋予id,则自动分配
            for (int i = 0; i < 3; i++) {
                myId = i;
                System.out.println("myId is " + i + " : " + Thread.currentThread().getName());
            }
        } else {
            for (int i = 0; i < 3; i++) {
                System.out.println("myId is " + i + " : " + Thread.currentThread().getName());
            }
        }
    }
}

在main函数中,我想使用三个thread调用它,因为synchronized关键字的关系,最后的理想结果应该是

myId is 0 : Thread-1
myId is 1 : Thread-1
myId is 2 : Thread-1
myId is 0 : Thread-0
myId is 1 : Thread-0
myId is 2 : Thread-0
myId is 0 : Thread-2
myId is 1 : Thread-2
myId is 2 : Thread-2

即所有的thread应该是锁定直至自身运行结束为止,才运行下一个
main函数如下:

public static void main(String[] args) {
     new Thread(new MultiThreadTest(1)).start();
     new Thread(new MultiThreadTest(2)).start();
     new Thread(new MultiThreadTest(3)).start();
}

但是实际结果却是这个样子

myId is 0 : Thread-2
myId is 0 : Thread-0
myId is 0 : Thread-1
myId is 1 : Thread-2
myId is 1 : Thread-0
myId is 2 : Thread-0
myId is 2 : Thread-2
myId is 1 : Thread-1
myId is 2 : Thread-1

很显然,各个线程之间的运行还是乱的,synchronized并没有起到任何作用。

为什么会这样?

原因在于main调用thread是,实际上是new了3个instances,这样一来,java就将之视为3个独立的程序(大概是这个意思,但是用词不准确)

我们现在来看看java对于synchronized的相关描述

synchronized has two effects:

  • First, it is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object.
  • Second, when a synchronized method exits, it automatically establishes a happens-before relationship with any subsequent invocation of a synchronized method for the same object. This guarantees that changes to the stat e of the object are visible to all threads.

注意,这里面的关键字是the same object,也就是说,synchronized的作用只针对同一个object或者说instance有效。而上面的main中,却一下子new了3个instance,对于java来说,相当于3个不同的object,而这三个objects分别只运行了一次,所以synchronized在这里面就毫无意义了,就算将run()函数前的synchronized去掉,结果也没有区别。

那么如何得到理想结果呢?

其实上面已经告诉我们答案了,就是the same object,无论你有多少个thread,只要调用的都是同一个instance,那么这个synchronized就会起作用。

如果main函数改成这样

public static void main(String[] args) {

    Runnable r = new MultiThreadTest();

    new Thread(r).start();
    new Thread(r).start();
    new Thread(r).start();
}

就能得到理想结果了。

你可能感兴趣的:(java,Class)