Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java同步方法_Java_Multithreading_Synchronization - Fatal编程技术网

Java同步方法

Java同步方法,java,multithreading,synchronization,Java,Multithreading,Synchronization,我有许多共享变量x,y,z,所有这些变量都可以在两个不同线程中运行的两个不同方法中进行修改。如果我将这两个方法声明为synchronized,那么它能保证变量x、y和z的一致性吗。或者我应该对每个变量单独使用一个锁吗 是的,您的方法将保证一致性,假设这些变量都是私有的,并且不在两个同步方法之外进行读写访问 请注意,如果在同步块之外读取这些变量,则可能会得到不一致的结果: class Foo { private int x; public synchronized void fo

我有许多共享变量x,y,z,所有这些变量都可以在两个不同线程中运行的两个不同方法中进行修改。如果我将这两个方法声明为synchronized,那么它能保证变量x、y和z的一致性吗。或者我应该对每个变量单独使用一个锁吗

是的,您的方法将保证一致性,假设这些变量都是私有的,并且不在两个同步方法之外进行读写访问

请注意,如果在同步块之外读取这些变量,则可能会得到不一致的结果:

class Foo {
    private int x;

    public synchronized void foo() {
        x = 1;
    }

    public synchronized void bar() {
        x = 2;
    }

    public boolean baz() {
        int a = x;
        int b = x;
        // Unsafe! x could have been modified by another thread between the two reads
        // That means this method could sometimes return false
        return a == b;
    }
}
编辑:更新以解决您对静态变量的评论

每个类都应该拥有自己的数据。如果类A允许通过公开变量来直接访问变量,那么它就不拥有自己的数据,并且执行线程安全变得非常困难

如果您这样做:

class A {
    private static int whatever;

    public static synchronized int getWhatever() {
        return whatever;
    }

    public static synchronized void setWhatever(int newWhatever) {
        whatever = newWhatever;
    }
}
那你就没事了

记住,synchronized在单个对象上强制执行互斥。对于同步方法,它是this或静态方法的Class对象。其他对象上的同步块不会相互干扰

class A {
    public synchronized void doSomething() {...}
}
class B {
    public synchronized void doSomethingElse() {...}
}
对doSomething的调用不会等待对doSomethingElse的调用,因为它们在不同的对象上是同步的:在这种情况下,A的相关实例和B的相关实例。类似地,对A的不同实例的两个对doSomething的调用不会相互干扰

class A {
    public synchronized void doSomething() {...}
}
class B {
    public synchronized void doSomethingElse() {...}
}

我强烈建议你去看看。这是一本极好的书,解释了Java线程和内存模型的所有微妙之处。

是的,您的方法将保证一致性,假设这些变量都是私有的,并且不在两个同步方法之外读取或写入

请注意,如果在同步块之外读取这些变量,则可能会得到不一致的结果:

class Foo {
    private int x;

    public synchronized void foo() {
        x = 1;
    }

    public synchronized void bar() {
        x = 2;
    }

    public boolean baz() {
        int a = x;
        int b = x;
        // Unsafe! x could have been modified by another thread between the two reads
        // That means this method could sometimes return false
        return a == b;
    }
}
编辑:更新以解决您对静态变量的评论

每个类都应该拥有自己的数据。如果类A允许通过公开变量来直接访问变量,那么它就不拥有自己的数据,并且执行线程安全变得非常困难

如果您这样做:

class A {
    private static int whatever;

    public static synchronized int getWhatever() {
        return whatever;
    }

    public static synchronized void setWhatever(int newWhatever) {
        whatever = newWhatever;
    }
}
那你就没事了

记住,synchronized在单个对象上强制执行互斥。对于同步方法,它是this或静态方法的Class对象。其他对象上的同步块不会相互干扰

class A {
    public synchronized void doSomething() {...}
}
class B {
    public synchronized void doSomethingElse() {...}
}
对doSomething的调用不会等待对doSomethingElse的调用,因为它们在不同的对象上是同步的:在这种情况下,A的相关实例和B的相关实例。类似地,对A的不同实例的两个对doSomething的调用不会相互干扰

class A {
    public synchronized void doSomething() {...}
}
class B {
    public synchronized void doSomethingElse() {...}
}

我强烈建议你去看看。这是一本极好的书,解释了Java线程和内存模型的所有微妙之处。

是的,它将是一致的

同步方法在执行之前获取监视器§17.1。 对于类静态方法,与该类关联的监视器 使用方法类的对象。对于实例方法 与此方法关联的监视器是为其创建方法的对象 已调用

看看这个


注意:-有一点您必须小心,一些程序员通常会落入这个陷阱,那就是同步的静态方法和同步的非静态方法之间没有联系

是的,这是一致的

同步方法在执行之前获取监视器§17.1。 对于类静态方法,与该类关联的监视器 使用方法类的对象。对于实例方法 与此方法关联的监视器是为其创建方法的对象 已调用

看看这个


注意:-您需要注意的一点是,当您在方法上进行同步时,几个程序员通常会陷入这样的陷阱:同步的静态方法和同步的非静态方法之间没有链接:

如果方法是静态的,则会对类对象进行锁定 如果方法是非静态的,则会对实例对象进行锁定。
只要锁一次只被一个线程占用,是的,执行您想要的操作是一致和安全的。

在方法上同步时:

如果方法是静态的,则会对类对象进行锁定 如果方法是非静态的,则会对实例对象进行锁定。
只要锁一次只被一个线程占用,是的,执行您想要的操作是一致和安全的。

这是主观的。行为取决于实例化线程的方式。如果两个线程在包含这些方法的类的同一实例上调用synchtonized方法,它们将阻塞。如果每个线程实例化一个包含方法的类的新对象,它们将不会阻塞,因为类的两个不同实例上会有两个锁

这是主观的。行为取决于环境

您实例化线程的方式。如果两个线程在包含这些方法的类的同一实例上调用synchtonized方法,它们将阻塞。如果每个线程实例化一个包含方法的类的新对象,它们将不会阻塞,因为类的两个不同实例上会有两个锁

已同步应用于实例而非方法。@Eng.Fouad。。。这意味着结果将是一致的。敢写一个答案吗?@Eng.Fouad:没错,但是你也可以声明一个要同步的方法。它在方法体周围插入了一个隐式的synchronized this。此外,您不仅必须同步修改变量的代码块,还必须同步读取变量的代码块。您在这里描述的是单个类吗?一个包含上述变量和两个方法的类?synchronized应用于实例而非方法。@Eng.Fouad。。。这意味着结果将是一致的。敢写一个答案吗?@Eng.Fouad:没错,但是你也可以声明一个要同步的方法。它在方法体周围插入了一个隐式的synchronized this。此外,您不仅必须同步修改变量的代码块,还必须同步读取变量的代码块。您在这里描述的是单个类吗?一个包含上述变量和两个方法的类?但是阻塞是坏的吗?僵局当然是。变量的无效读取肯定是错误的!当我说阻塞时,我的意思是等待获得锁。这就是为什么首先引入同步,以阻止线程以不可预知的方式跳转,并避免竞争条件。如果线程锁定在单个实例上,则不会有任何无效读取。@bot:谢谢。那么解决办法是什么呢。变量上的单个锁?@Bot:您无法获取变量上的锁。这有点误导。synchronized关键字获取对象的监视器。如果一个方法被声明为synchronized,那么它将在该方法的持续时间内隐式获取该方法的监视器。完全可以接受使用同步块来获取不同变量的监视器。@Bot:这不是主观的,也不取决于线程的实例化方式。synchronized的行为在语言规范中有很好的定义,如何获取线程对象是不相关的。如果两个线程访问不同的对象,则不可能存在争用条件或无效读取。所以我们只需要考虑两个线程访问同一个对象的情况。只要关键部分(即对共享数据的读/写)受到适当对象上的同步保护,就不会有问题。但阻塞是坏的吗?僵局当然是。变量的无效读取肯定是错误的!当我说阻塞时,我的意思是等待获得锁。这就是为什么首先引入同步,以阻止线程以不可预知的方式跳转,并避免竞争条件。如果线程锁定在单个实例上,则不会有任何无效读取。@bot:谢谢。那么解决办法是什么呢。变量上的单个锁?@Bot:您无法获取变量上的锁。这有点误导。synchronized关键字获取对象的监视器。如果一个方法被声明为synchronized,那么它将在该方法的持续时间内隐式获取该方法的监视器。完全可以接受使用同步块来获取不同变量的监视器。@Bot:这不是主观的,也不取决于线程的实例化方式。synchronized的行为在语言规范中有很好的定义,如何获取线程对象是不相关的。如果两个线程访问不同的对象,则不可能存在争用条件或无效读取。所以我们只需要考虑两个线程访问同一个对象的情况。只要关键部分(即对共享数据的读/写)受到适当对象上同步的保护,就不会出现问题。您确定吗?如果每个线程实例化一个新的Foo呢?明白了吗?@cameron:假设foo方法在foo类中,而bar方法在另一个类中,比如说class bar。假设变量x不是私有的,我在foo和bar方法中都对其进行了修改。那么它能保证一致性吗?@Ashwin不,它不能。看看我的答案。只有在同一对象上获得锁时,才能确保一致性。@bot:谢谢。那么解决办法是什么呢。变量上的单个锁?@bot:Gotcha?不。如果每个线程实例化一个新的Foo,那么它们就不会相互干扰。x是一个实例变量,因此如果有不同的Foo实例,那么每个实例都有自己的x。如果每个对象仅由一个线程访问,则无需担心线程安全。您确定吗?如果每个线程实例化一个新的Foo呢?明白了吗?@cameron:假设foo方法在类foo中,而bar方法在另一个类sa中
y级酒吧。假设变量x不是私有的,我在foo和bar方法中都对其进行了修改。那么它能保证一致性吗?@Ashwin不,它不能。看看我的答案。只有在同一对象上获得锁时,才能确保一致性。@bot:谢谢。那么解决办法是什么呢。变量上的单个锁?@bot:Gotcha?不。如果每个线程实例化一个新的Foo,那么它们就不会相互干扰。x是一个实例变量,因此如果有不同的Foo实例,那么每个实例都有自己的x。如果每个对象仅由一个线程访问,则无需担心线程安全。您确定吗?如果每个线程实例化一个包含线程将调用的方法的类的新实例会怎么样?@bot:如果是这样,那么OP就不会有共享变量被不同的线程修改,正如问题所说,OP讨论的是两个不同类的两个不同实例共享一个变量,而不是一个类的单个实例与两个线程共享。你的回答没有回答OP的问题,我的回答是不正确的。你确定吗?如果每个线程实例化一个包含线程将调用的方法的类的新实例会怎么样?@bot:如果是这样,那么OP就不会有共享变量被不同的线程修改,正如问题所说,OP讨论的是两个不同类的两个不同实例共享一个变量,而不是一个类的单个实例与两个线程共享。你的回答没有回答OP的问题,我的回答是不正确的。