无法理解java中的Synchronized块

时间:2016-10-03 05:29:15

标签: java multithreading synchronization

我正在尝试研究java中的线程同步,我开始了解synchronized块。我可能会问一个愚蠢的问题,因为我对线程同步知之甚少,但在这个程序中,我不理解块的行为。

class Table {
    void printTable(int n) { //method not synchronized
        for(int i=1; i<=10; i++) {
            System.out.println(n + " * " + i + " = " + n*i);
            try {
                Thread.sleep(500);
            } catch(Exception e) {
                System.out.println(e);
            }
        }
        System.out.println("Table of " + n + " is completed.");
    }
}

class MyThread extends Thread {
    Table t;
    int num;

    MyThread(Table t, int num) {
        this.t = t;
        this.num = num;
    }

    public void run() {
      synchronized(t) {
        t.printTable(num);
      }
    }
}

class TestSynchronization {
    public static void main(String[] args) {
        Table obj = new Table(); //only one object
        MyThread t1;
        MyThread t2;

        t1 = new MyThread(obj, 10);
        t2 = new MyThread(obj, 17);

        t1.start();
        t2.start();
    }
}

它的输出是这样的:

10 * 1 = 10
10 * 2 = 20
10 * 3 = 30
10 * 4 = 40
10 * 5 = 50
Table of 10 is completed.
17 * 1 = 17
17 * 2 = 34
17 * 3 = 51
17 * 4 = 68
17 * 5 = 85
Table of 17 is completed.

这似乎是正确的,但当我尝试通过从run方法中删除synchronized块并将其应用到obj void main对象时,它会显示不同的输出。

class Table {
    void printTable(int n) { //method not synchronized
        for(int i=1; i<=5; i++) {
            System.out.println(n + " * " + i + " = " + n*i);
            try {
                Thread.sleep(500);
            } catch(Exception e) {
                System.out.println(e);
            }
        }
        System.out.println("Table of " + n + " is completed.");
    }
}

class MyThread extends Thread {
    Table t;
    int num;

    MyThread(Table t, int num) {
        this.t = t;
        this.num = num;
    }

    public void run() {
        t.printTable(num);
    }
}

class TestSynchronization {
    public static void main(String[] args) {
        Table obj = new Table(); //only one object
        MyThread t1;
        MyThread t2;

        synchronized(obj) {
        t1 = new MyThread(obj, 10);
        t2 = new MyThread(obj, 17);
        }

        t1.start();
        t2.start();
    }
}

输出:

10 * 1 = 10
17 * 1 = 17
10 * 2 = 20
17 * 2 = 34
17 * 3 = 51
10 * 3 = 30
17 * 4 = 68
10 * 4 = 40
10 * 5 = 50
17 * 5 = 85
Table of 17 is completed.
Table of 10 is completed.

为什么这不适用于第二种情况请解释我。

如果可能的话,还建议我使用void main中的synchronized块来获得相同输出的方式。

3 个答案:

答案 0 :(得分:1)

差异为 时获取Table类对象的lock

在第一个示例中,在MyThread类的实例中获取了对Table对象的锁定。假设MyThread类的第一个实例获取了表对象锁,MyThread类的其他实例将无法获取对表对象的锁,直到第一个释放它为止, 线程级同步

在你的第二个例子中,对象的锁是由驱动程序获取的,所以从技术上讲,这个级别没有并发问题,因为锁是绑定到驱动程序而不是单个线程,这实际上是一种 流程级同步

答案 1 :(得分:0)

同步块是一个Room,Synchronized块应用于对象。 在第一个示例中,同步块应用于类表对象。 当任何线程试图访问该方法时,它必须首先进入同步块,就像一个人进入房间,当像t1这样的线程进入块时,房间被锁定,直到t1执行完毕,并且只有在那之后线程t2进入房间。

如果没有同步块,则线程相互交错,因此输出不同,如果t1在t2开始之前完成执行,有时输出可能是正确的但是在大应用的情况下它会干扰并导致不同的输出正如你在第二个例子中提到的那样。 因此,为了防止这种交错,我们使用synchronized块或thrcead安全类,如阻塞队列等。

答案 2 :(得分:0)

同步块

   synchronized(mutex){
     x =y;
     y=z;
   }

互斥=相互排斥。 可以由共享相同对象的线程列表中的一个线程执行的块,即mutex

首先,互斥锁是对象,java中的每个对象都有一个名为lock的半连接。

如果线程A和B共享互斥锁为c 然后在进入同步块之前进行线程A必须获取锁定 即在入学前获得

并且在获取之前发布,即如果一个线程已经获得了锁,则另一个线程必须等到第一个线程不释放锁。

同步块的另一个特性是获取锁的每个线程需要直接从主存储器读取块中涉及的所有变量而不是缓存中的停顿值,并且必须在更改之前将其写入主存储器,然后再离开块

即。在获取和内存写入发布之前发生变量值更新,因此下一个线程将具有要处理的最新值。