简体   繁体   English

使用相同和不同类实例的两个线程之间的同步?

[英]Synchronization between two threads using same and different instance of class?

I would like to clear few doubts and extending question from here - synchronization in two methods in the same class .我想从这里清除一些疑问并扩展问题 - 同一类中两种方法的同步

public class Demo {
    public synchronized void methodA(){
        System.out.println("Method A");
    }
    public synchronized void methodB(){
        System.out.println("Method B");
    }

    public static void main(String[] args) {
        Demo demo = new Demo();
        Demo demo1 = new Demo();

        Thread thread1 = new Thread(() -> demo.methodA());
        thread1.start();

        Thread thread2 = new Thread(() -> demo1.methodB());
        thread2.start();
    }
}

locks work at the instance level, not at the class level.锁在实例级别工作,而不是在类级别。

Case-1: For each instance of Demo at most one between method1 and method2 can be running at any given moment.案例 1:对于每个Demo实例,method1 和 method2 之间最多有一个可以在任何给定时刻运行。 This is clear.这是清楚的。

Case-2: Two different instances are calling two separate method, will still the thread block each other?案例 2:两个不同的实例正在调用两个单独的方法,线程仍然会互相阻塞吗?

Using Static Synchronized the same method -使用静态同步相同的方法 -

public class Demo {
    public static synchronized void methodA(){
        System.out.println("Method A");
    }
    public static synchronized void methodB(){
        System.out.println("Method B");
    }

    public static void main(String[] args) {
        Demo demo = new Demo();
        Demo demo1 = new Demo();

        Thread thread1 = new Thread(() -> demo.methodA());
        thread1.start();

        Thread thread2 = new Thread(() -> demo1.methodB());
        thread2.start();
    }
}

Case-3: Say same instance of demo class demo is used to call two separate method, will they block each other?案例3:假设demo类demo同一个实例被用来调用两个单独的方法,它们会互相阻塞吗?

Case-4: Say different instances of Demo class demo and demo1 is used to call two separate method will they still block each other?案例 4:假设 Demo 类demodemo1不同实例用于调用两个单独的方法,它们仍然会互相阻塞吗?

Case2 No, the lock is for method's object. Case2 不,锁是方法的对象。 Each instance keeps a separate lock每个实例都有一个单独的锁

Case3 Yes, the static method has association with a class not a object, so the lock is for the Class object. Case3 是的,静态方法关联的是类而不是对象,所以锁是针对Class对象的。 They block each other他们互相阻止

Case4: Yes, since it's the class object, same result in invoking it on different instances Case4:是的,因为它是类对象,所以在不同的实例上调用它的结果相同

The synchronized keyword on a method is in just about every relevant fashion simply syntax sugar.方法上的synchronized关键字几乎在所有相关方式中都是简单的语法糖。 So let's desugar this, that makes it more clear:因此,让我们对此进行脱糖,使其更加清晰:

class Test {
  synchronized void foo() {
    hello();
  }
}

// desugars to:

class Test {
  void foo() {
    synchronized (this) {
      hello();
    }
  }
}

And if we involve static:如果我们涉及静态:

class Test {
  static synchronized void staticFoo() {
    hello();
  }
}

// desugars to:

class Test {
  static void staticFoo() {
    synchronized (Test.class) {
      hello();
    }
  }
}

Now we just need to explain what synchronized() does, and perhaps what Test.class does.现在我们只需要解释synchronized()作用,也许还有Test.class作用。

Every object in java is also a locking object. java中的每个对象也是一个锁定对象。 It basically works like this:它基本上是这样工作的:

  • Every object has a hidden field that you cannot access, at all, but it does exist.每个对象都有一个您根本无法访问的隐藏字段,但它确实存在。 It is of type Thread and is called monitor .它属于Thread类型,称为monitor It also has a second hidden, in accessible field int monitorCount;它还有一个隐藏的,在可访问字段int monitorCount; . .
  • Objects initially start out with a count of 0 and a null value for the monitor field.对象最初以 0 计数和monitor字段的null值开始。
  • synchronized(expr) { means one of three things: synchronized(expr) {表示三件事之一:
  • If the object you find when you resolve expr currently has monitor == null , then execute: monitor = Thread.currentThread(); monitorCount = 1;如果您在解析expr时找到的对象当前具有monitor == null ,则执行: monitor = Thread.currentThread(); monitorCount = 1; monitor = Thread.currentThread(); monitorCount = 1; , and enter the {} block. ,然后进入{}块。
  • If the object you find when you resolve expr currently has monitor == Thread.currentThread() , then simply execute monitorCount++ and enter the block.如果您在解析expr时找到的对象当前具有monitor == Thread.currentThread() ,则只需执行monitorCount++并进入块。
  • Otherwise (so, monitor 's value is some other thread), freeze this thread until monitor is null , then act as per the first rule.否则(因此, monitor的值是某个其他线程),冻结该线程直到monitornull ,然后按照第一个规则进行操作。
  • ... but of course the above 3 things occur atomically: The JVM guarantees that any 2 threads don't both draw the conclusion that monitor is null simultaneously or other such shenanigans. ...但当然上述 3 件事是原子发生的:JVM 保证任何 2 个线程不会同时得出monitornull或其他此类恶作剧的结论。 In other words, if you actually wrote this code, it wouldn't work, because you don't get that '... but atomically' guarantee, but synchronized does provide it.换句话说,如果你真的写了这段代码,它就不会工作,因为你没有得到“......但原子”的保证,但synchronized确实提供了它。

Test.class is an exotic but entire valid java construct. Test.class是一个奇特但完整有效的 java 构造。 Try it:尝试一下:

In java, any class has exactly one instance of the class java.lang.Class associated with it.在 java 中,任何类都只有一个与之关联的java.lang.Class类的实例。 Given any object you can get it using obj.getClass() .给定任何对象,您都可以使用obj.getClass()获取它。 If you don't have an instance of a class, but you do know exactly what class you're talking about, the language construct ThatClass.class will get you that instance just the same.如果您没有类的实例,但您确实知道您在谈论什么类,那么语言构造ThatClass.class将为您提供相同的实例。 Let's try it:让我们试试看:

public static void main(String[] args) {
  Class<?> stringClass = String.class;
  System.out.println(stringClass);
  System.out.println("".getClass() == String.class); // 'true'.
}

Note that without custom classloaders, these instances are singletons.请注意,如果没有自定义类加载器,这些实例是单例。

This then explains static synchronized : They're all locking on the exact class.这然后解释了static synchronized :它们都锁定在确切的类上。 Note that this class stuff doesn't inherit: If you have:请注意,此类内容不会继承:如果您有:

class Parent {
  static synchronized void parentMethod() {}
}

class Child extends Parent {
  static synchronized void childMethod() {}
}

Then thread A can be executing parentMethod whilst at the same time thread B is executing childMethod as they are locking on different objects.然后线程 A 可以执行 parentMethod 而同时线程 B 正在执行 childMethod 因为它们锁定在不同的对象上。 (namely, Child.class , and Parent.class . (即Child.classParent.class

With that knowledge:有了这些知识:

Case2: No, instance1.monitor == threadA; Case2:不, instance1.monitor == threadA; and instance2.monitor == threadB;instance2.monitor == threadB; , no problem. , 没问题。 They won't block each other.他们不会互相阻拦。

Case 3: Yes, as there is only one Demo.class.monitor`, and that can only be threadA or threadB.情况 3:是的,因为只有一个 Demo.class.monitor`,并且只能是 threadA 或 threadB。 The one that it isn't, can't enter these methods and has to wait.不是的,不能进入这些方法,必须等待。

Case 4: Same as 3.情况 4:同 3。

Here's a couple of examples to - hopefully - make it more obvious.这里有几个例子 - 希望 - 让它更明显。

First the Instance Demo:首先是实例演示:

/**
 * Instance : the Threads run independently, synchronizing on the Instances
 */
import java.util.Random;
import java.util.stream.IntStream;

public final class Demo {

    private        final Random randomA = new Random();
    private        final Random randomB = new Random();

    private        void common(final String label, final Random random) {
        IntStream.range(0, 10).forEach(n -> {

            final String       thread = Thread.currentThread().getName();

            System.out.println(thread + " Method " + label + "-1 n=" + n);

            try {Thread.sleep(random.nextInt(100));} catch (final InterruptedException e) {}

            System.out.println(thread + " Method " + label + "-2 n=" + n + "\n");

            try {Thread.sleep(random.nextInt(100));} catch (final InterruptedException e) {}
        });
    }

    private        synchronized void methodA() {common("A_", randomA);}
    private        synchronized void methodB() {common("_B", randomB);}

    public  static void main(final String[] args) {

        final Demo demoB = new Demo();

        new Thread(() -> new Demo().methodA(), "[Thread_Aa_]").start(); // Comment out
//      new Thread(() ->     demoB .methodA(), "[Thread__Ba]").start(); // Un-Comment
        new Thread(() ->     demoB .methodB(), "[Thread__Bb]").start();
    }
}

And now, the Static Demo:现在,静态演示:

/**
 * Static : the Threads block each other, synchronizing on the Class
 * 3 & 4) methodA & methodB are never interrupted
 * 3 & 4) calling static Methods from the Instance gives a Compiler Warning
 *        & actually executes DemoStatic.methodA(...) or DemoStatic.methodB(...)
 *        Warning:
 *        The static method x(.) from the type Y should be accessed in a static way
 */
import java.util.Random;
import java.util.stream.IntStream;

public final class DemoStatic {

    private static final Random randomA = new Random();
    private static final Random randomB = new Random();

    private static void common(final String label, final Random random, final int n) {

        final String       thread = Thread.currentThread().getName();

        System.out.println(thread + " Method " + label + "-1 n=" + n);

        try {Thread.sleep(random.nextInt(100));} catch (final InterruptedException e) {}

        System.out.println(thread + " Method " + label + "-2 n=" + n + "\n");

        try {Thread.sleep(random.nextInt(100));} catch (final InterruptedException e) {}
    }

    public static synchronized void methodA(final int n) {common("A_", randomA, n);}
    public static synchronized void methodB(final int n) {common("_B", randomB, n);}

    public static void main(final String[] args) {

//      @SuppressWarnings("static-access")
        final Runnable loopA = () -> IntStream.range(0, 10).forEach(n -> new DemoStatic().methodA(n));
        final Runnable loopB = () -> IntStream.range(0, 10).forEach(n ->     DemoStatic  .methodB(n));

        new Thread(loopA, "[Thread_A_]").start();
        new Thread(loopB, "[Thread__B]").start();
    }
}

暂无
暂无

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

相关问题 在相同类的两个不同实例上定义的线程之间的通信? - Communication between threads defined on two different instances of same class? 如何在不同的线程中执行两种接受相同 class 的可运行实例的方法? - How to execute two methods accepting runnable instance of same class in different threads? Java或Android中不同线程/进程之间的同步? - Synchronization between different threads/processes in Java or Android? DAO和线程之间的同步 - DAO and Synchronization between threads 使用以下类的实例在线程之间共享有什么问题? - What is the problem with using an instance of the following class to share between threads? Java:当线程池中的所有线程都完成时通知主 class / object 在不同线程中的相同实例 - Java: notify main class when all threads in threadpool are finished / same instance of object in different threads 如何在两个线程之间共享对象(线程同步)? - How to Share a Object between two threads (Thread Synchronization)? 同步:线程以相同的顺序执行两个关键部分 - synchronization : Threads execute two critical sections in same order 可以使用两个线程访问LinkedList中同一对象的不同属性吗? - Possible to access to different attributes of the same object in a LinkedList using two Threads? 我可以使用两个不同的线程在同一个套接字上读写吗? - Can I read and write on the same socket using two different threads?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM