简体   繁体   English

Java Synchronized会同步一个类的所有同步方法吗?

[英]Java Synchronized synchronizes all synchronized methods of a class among each other?

I've a question about synchronization in java. 我有一个关于java同步的问题。 In the following Java program I dont get any output. 在下面的Java程序中,我没有得到任何输出。 But, if I remove the synchronized statement from the method IFoo.s() I'll get some output. 但是,如果我从方法IFoo.s()中删除synchronized语句,我将获得一些输出。 It seems like the methods IFoo.setP() and IFoo.s() are synchronized among each other. 似乎方法IFoo.setP()和IFoo.s()在彼此之间是同步的。 But 'synchronized' should only prevent that two threads call the synchronized method at the same time, right? 但是'synchronized'应该只能防止两个线程同时调用synchronized方法,对吧?

package com.example.relectiontest;

import java.awt.Point;
import java.util.Random;

public class Main {

public static void main(String[] args) throws Exception{
    final IFoo f = new IFoo();
    Runnable r = new Runnable() {
        public void run() {
            Random r = new Random();
            int a = r.nextInt(5)+1;
            for(int i=0;i<1000000;++i){
                f.setP(a);
            }
        }
    };
    Runnable r2 = new Runnable() {
        public void run() {
            for(int i=0;i<1000000;++i){
                f.s();
            }
        }
    };
    Thread T1 = new Thread(r, "T1");
    Thread T2 = new Thread(r, "T2");
    Thread T3 = new Thread(r2, "T3");
    T3.start();
    T1.start();
    T2.start();
}

private static class IFoo{
    private Point p = new Point();

    public synchronized void setP(int a){
        //System.out.println("p1 "+Thread.currentThread());
        p.x = a;
        p.y = p.x;
        int x = p.x , y = p.y;
        if(x != y)
            System.out.println(Thread.currentThread()+"\t"+x+" "+y);
        //System.out.println("p2 "+Thread.currentThread());
    }

    public synchronized void s(){
        //System.out.println("s");
        p.x = 0;
    }
}
}

So, why I cant see any output? 那么,为什么我看不到任何输出?

regards 问候

Because thanks to synchronization x != y will never be true. 因为同步x != y永远不会成真。

In your unsynchronized version s() has the chance of setting px to 0 every once in a while (even though it's not synchronized properly). 在你的非同步版本中, s()有可能每隔一段时间将px设置为0(即使它没有正确同步)。

In the synchronized version s() must wait until setP is finished (since they're both synchronized, sharing the implicit this lock), and thanks to the logic in setP the condition can not be true. 在同步版本中, s()必须等到setP完成(因为它们都是同步的,共享隐式的this锁),并且由于setP的逻辑,条件不能为真。

Your example is overly complex. 你的例子过于复杂。 You can write it out as follows (adding synchronized on both methods to see that nothing will be printed): 您可以按如下方式编写它(在两种方法上添加同步以查看将不会打印任何内容):

private static class IFoo {
    volatile int x = 0;
    public void setP(int a) {
        x = a;
        if(x != a)
            System.out.println("Someone changed x!");
    }

    public void s() {
        x = 0;
    }
}

Also note that static synchronized methods synchronize on the Class object since they have no this . 另请注意,静态同步方法在Class对象上同步,因为它们没有this Instance and static methods therefore won't lock each other unless you explicitly synchronize on a common lock. 因此,除非您在公共锁上显式同步,否则实例和静态方法不会相互锁定。

In Java all synchronized calls are synchronized on an object. 在Java中,所有synchronized调用都在对象上同步。 For instance methods, they object is the class instance - so in your case setP and s are both synchronized on the instance of IFoo . 对于实例方法,它们的对象是类实例 - 所以在你的情况下, setPs都在IFoo的实例上同步。

This allows you to control access to shared fields which are accessed through more than one method. 这允许您控制对通过多种方法访问的共享字段的访问。 With your code, this will be exactly what you need - you need to make sure you don't have one thread in setP changing the state while another in s is reading it. 使用您的代码,这正是您所需要的 - 您需要确保setP没有一个线程改变状态而s另一个正在读取它。

If you prefer finer control you can use synchronized blocks, which allow you to specify the object to lock on: 如果您更喜欢更精细的控制,可以使用synchronized块,它允许您指定要锁定的对象:

private final Object o=new Object();

public void method(){
    synchronized (o){
        //Synchronized code
    }
}

This is the generally generally recommended approach - it allows you to encapsulate your lock, so you don't risk some other class interfering with your locks and potentially DOSing your code. 这是通常建议的方法 - 它允许您封装锁,因此您不会冒一些其他类干扰您的锁并可能使代码处于DOS的风险。

Static methods are synchronized on the class object (such as IFoo.class ). 静态方法在类对象上同步(例如IFoo.class )。

From documentation : 来自文档

making these methods 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 state of the object are visible to all threads. 这可以保证对所有线程都可以看到对象状态的更改。

The output will be displayed only when: 只有在以下情况下才会显示输出:

 if(x != y) 

Because in lines: 因为在行:

 p.x = a;
 p.y = p.x;
 int x = p.x , y = p.y;

You make x == y that output is not displayed. 你使x == y表示不显示输出。

When you remove synchronization keyword from s method - the threads sometimes set x to 0 and this make if(x != y) - to true. 从s方法中删除同步关键字时 - 线程有时会将x设置为0,这会使if(x!= y) - 为true。 and output is visible. 和输出是可见的。

Because normally you shouldn't get any output as x should be equal to y. 因为通常你不应该得到任何输出,因为x应该等于y。 However, when you remove the synchronized keyword, two threads execute at the same time and you may get an output if s() executes between py=px and x=px statements. 但是,当您删除synchronized关键字时,两个线程同时执行,如果s()在py = px和x = px语句之间执行,则可能会得到输出。

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

相关问题 Java同步方法是否在对象上同步或使用标志 - Does java synchronized methods synchronizes on object or uses flag 在Java中,当对象中的一个方法“同步”时,所有方法都是“同步”的吗? - In Java when one methods in an object is 'synchronized' are all methods 'synchronized'? 对于同一 object 的所有同步方法,Java 同步锁定密钥是否相同? - Is Java synchronized lock key the same for all synchronized methods of the same object? 令人困惑的Java同步方法,synced(this)和synced类 - Confusing Java synchronized method, synchronized(this), and synchronized class Java在同步块中调用其他方法 - Java calling other methods in synchronized block Java 是否还保证同步之前的所有变量更改对于在同一对象上同步的下一个线程都是可见的? - Does Java also guarantee that all variable changes before synchronized will be visible to the next thread which synchronizes on same object? 同步是否适用于 class 中的所有方法或仅适用于 1? - Does synchronized work for all methods in a class or only 1? Java:是否需要同步所有静态方法? - Java: Do all static methods need to be synchronized? 所有Java Properties的方法是否完全同步? - Are all Java Properties' methods fully synchronized? Java类的同步方法中不尊重Mutex - Mutex not being respected in synchronized methods in Java class
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM