简体   繁体   English

同步块如何工作?

[英]how synchronized block works?

I am learning multi threading. 我正在学习多线程。 I've written a program using synchronization to print table of 10 and 5 using two threads. 我编写了一个使用同步程序来使用两个线程打印10和5表的程序。 While synchronized method is giving me expected result, synchronized block isn't. 虽然同步方法给了我预期的结果,但同步块却没有。 What am i doing wrong? 我究竟做错了什么?

public class SynchronizationDemo {

public static void main(String[] args) {
    Thread1 t=new Thread1(10);
    Thread1 t1=new Thread1(5);
    Thread thread1=new Thread(t);
    Thread thread2=new Thread(t1);
    thread1.start();
    thread2.start();
}
//synchronized method
/*public static synchronized void printTable(int num) {
    for (int i = 1; i <= 10; i++) {
        System.out.println(num*i);
        try {
            Thread.sleep(1000);
        }catch(InterruptedException ie){
            ie.printStackTrace();
        }
    }
}*/
//synchronized block
public void printTable(int num)
{
    synchronized(this){
        for (int i = 1; i <= 10; i++) {
            System.out.println(num*i);
            try {
                Thread.sleep(1000);
            }catch(InterruptedException ie){
                ie.printStackTrace();
            }
        }
     }
   }
 }

class Thread1 implements Runnable{
    int num;
    Thread1(int num){
        this.num=num;
    }
    @Override
    public void run() {
        new SynchronizationDemo().printTable(num);
    }
}

Output of the code : 10 5 10 20 30 15 20 40 25 50 60 30 70 35 40 80 90 45 100 50 代码输出:10 5 10 20 30 15 20 40 25 50 60 30 70 35 40 80 90 45 100 50

Expected output: 10 20 30 40 50 60 70 80 90 100 5 10 15 20 25 30 35 40 45 50 预期输出:10 20 30 40 50 60 70 80 90 100 5 10 15 20 25 30 35 40 45 50

The main difference between the two approaches is in a small but important detail. 两种方法之间的主要区别在于小而重要的细节。

  • Your synchronized block is synchronizing on this . 您的同步块同步在this

  • Your synchronized method (the commented out one!) is a static method. 您的同步方法(已注释掉的方法!)是static方法。 That means that it is synchronizing on the SynchronizationDemo class object!! 这意味着它正在SynchronizationDemo类对象上进行SynchronizationDemo

But that doesn't explain it all. 但这并不能解释全部。 The other thing is the way that you are calling the method. 另一件事是调用方法的方式。

    new SynchronizationDemo().printTable(num);

You are creating a new instance and then calling the method on it. 您正在创建一个新实例,然后在其上调用该方法。

  • When you call the static method, it makes no difference which instance you use ... because you are synchronizing on the Class object. 调用静态方法时,使用哪个实例没有区别...,因为您正在Class对象上进行同步。

  • When you call the instance method, the instances are different, and therefore there is no mutual exclusion at all. 当您调用实例方法时,实例是不同的, 因此根本没有相互排斥。 You only get mutual exclusion and proper synchronization when the two threads synchronize on the same object. 当两个线程在同一对象上同步时,您只会得到互斥和正确的同步。

You are using synchronized keyword in two different contexts. 您在两个不同的上下文中使用synchronized关键字。

  1. static synchronized method waits & gets a lock at SynchronizationDemo class level and there is only one lock for that class. static synchronized方法在SynchronizationDemo类级别等待并获得一个锁,并且该类只有一个锁。 So all the instances of that class will have to wait for that lock in a sequence. 因此,该类的所有实例都必须按顺序等待该锁。

  2. synchronized(this) block (or even a method) waits and gets a lock of objects of SynchronizationDemo class and there is a lock per each object. synchronized(this)块(甚至一个方法)等待并获取SynchronizationDemo类的对象锁,每个对象都有一个锁。 As each run() method creates its own instance new SynchronizationDemo() , that method does not need to wait until other methods are completed. 当每个run()方法创建其自己的new SynchronizationDemo()实例new SynchronizationDemo() ,该方法无需等待其他方法完成即可。

Try changing your Thread1 class by passing an object. 尝试通过传递对象来更改Thread1类。

class Thread1 implements Runnable{
    SynchronizationDemo demo;
    int num;

    Thread1(SynchronizationDemo demo, int num){
        this.demo = demo;
        this.num = num;
    }

    @Override
    public void run() {
        demo.printTable(num);
    }
}

Now, you can pass the same object of SynchronizationDemo class to both threads as below. 现在,您可以将SynchronizationDemo类的相同对象传递给两个线程,如下所示。

public static void main(String[] args) {
    SynchronizationDemo demo = new SynchronizationDemo();
    Thread1 t=new Thread1(demo, 10);
    Thread1 t1=new Thread1(demo, 5);
    Thread thread1=new Thread(t);
    Thread thread2=new Thread(t1);
    thread1.start();
    thread2.start();
}

The difference is that you also changed the method to no longer be static . 不同之处在于您还将方法更改为不再是static

public static synchronized void printTable(int num) { }

This locks on the class, not on any single instance . 锁定在类上,而不在任何单个实例上

The equivalent synchronized block would be 等效的同步块将是

synchronized(SynchronizationDemo.class){
}

So even if you have two instances, they are still using the same lock (because they are both of the same class), whereas a synchronized(this) locks on two independent objects. 因此,即使您有两个实例,它们仍然使用相同的锁(因为它们都属于同一类),而synchronized(this)锁定两个独立的对象。

You are creating new instance of SynchronizationDemo 's object in run() method of thread. 您正在线程的run()方法中创建SynchronizationDemo对象的新实例。

@Override
public void run() {
    new SynchronizationDemo().printTable(num);
}

So each thread has a new object. 因此,每个线程都有一个新对象。 So in SynchronizationDemo.class synchronized blocks are useless if two or more thread not access to same object. 因此,在SynchronizationDemo.class中,如果两个或多个线程无法访问同一对象,则同步块是无用的。 Because of that threads works different object and each thread print out its number. 因此,线程工作于不同的对象,并且每个线程都打印出其编号。

Run your code 2 or more times , you can see the different output , if thread1 works earlier than thread2 or not. 如果thread1thread2早工作,请运行两次或两次以上的代码,可以看到不同的输出。

You should use static synchronized keyword with printTable method ; 您应该将static synchronized关键字与printTable方法一起使用;

public static synchronized  void printTable(int num){
     //do sth.
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM