我试图研究Java中的线程同步,后来才知道同步块。我可能会问一个愚蠢的问题,因为我对线程同步了解不多,但是在此程序中,我无法理解该块的行为。

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方法中删除同步块并将其应用到objvoid 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中的同步块来获得相同输出的方式。

最佳答案

区别在于在何处以及何时获取Table类对象的lock

在第一个示例中,对Table对象的锁定是在MyThread类的实例内部获取的。假设MyThread类的第一个实例获取表对象锁,则MyThread类的其他实例将无法获取对表对象的锁,直到第一个实例又将其释放,即线程级同步。

在第二个示例中,对对象的锁定是由驱动程序获取的,因此从技术上讲,在此级别上没有并发问题,因为该锁定与驱动程序而不是与各个线程无关,这实际上是一种过程。级同步。

10-07 13:23
查看更多