Java Synchronized 将 class 的所有同步方法彼此同步?
Java Synchronized synchronizes all synchronized methods of a class among each other?
我对 java 中的同步有疑问。在下面的 Java 程序中,我没有得到任何输出。但是,如果我从方法 IFoo.s() 中删除同步语句,我将得到一些输出。 IFoo.setP() 和 IFoo.s() 方法似乎彼此同步。但是'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;
}
}
}
那么,为什么我看不到任何输出?
问候
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.
因为通常你不应该得到任何输出,因为 x 应该等于 y。
但是,当您删除 synchronized 关键字时,两个线程同时执行,如果 s() 在 p.y=p.x 和 x=p.x 语句之间执行,您可能会得到一个输出。
因为同步 x != y
永远不会是真的。
在您的未同步版本中,s()
有机会每隔一段时间将 p.x 设置为 0(即使未正确同步)。
在同步版本中 s()
必须等到 setP
完成(因为它们都是同步的,共享隐式 this
锁),并且由于 this
中的逻辑=14=] 条件不成立。
您的示例过于复杂。可以这样写出来(在两种方法上都加上synchronized,看什么都不打印):
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;
}
}
另请注意,静态同步方法在 Class
对象上进行同步,因为它们没有 this
。因此,实例和静态方法不会相互锁定,除非您在公共锁上显式同步。
只有在以下情况下才会显示输出:
if(x != y)
因为在行中:
p.x = a;
p.y = p.x;
int x = p.x , y = p.y;
你使 x == y 不显示输出。
当您从 s 方法中删除同步关键字时 - 线程有时会将 x 设置为 0,这会使 if(x != y) - 为真。并且输出是可见的。
在 Java 中,所有 synchronized
调用都在一个对象上同步。对于实例方法,它们的对象是 class 实例 - 因此在您的情况下 setP
和 s
都在 IFoo
.
的实例上同步
这允许您控制对通过多种方法访问的共享字段的访问。对于您的代码,这正是您所需要的——您需要确保 setP
中没有一个线程正在更改状态,而 s
中的另一个线程正在读取状态。
如果您喜欢更精细的控制,您可以使用同步块,它允许您指定要锁定的对象:
private final Object o=new Object();
public void method(){
synchronized (o){
//Synchronized code
}
}
这是通常的 generally recommended approach - 它允许您封装您的锁,因此您不会冒其他 class 干扰您的锁并可能对您的代码进行 DOS 的风险。
静态方法在 class 对象(例如 IFoo.class
)上同步。
我对 java 中的同步有疑问。在下面的 Java 程序中,我没有得到任何输出。但是,如果我从方法 IFoo.s() 中删除同步语句,我将得到一些输出。 IFoo.setP() 和 IFoo.s() 方法似乎彼此同步。但是'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;
}
}
}
那么,为什么我看不到任何输出?
问候
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.
因为通常你不应该得到任何输出,因为 x 应该等于 y。 但是,当您删除 synchronized 关键字时,两个线程同时执行,如果 s() 在 p.y=p.x 和 x=p.x 语句之间执行,您可能会得到一个输出。
因为同步 x != y
永远不会是真的。
在您的未同步版本中,s()
有机会每隔一段时间将 p.x 设置为 0(即使未正确同步)。
在同步版本中 s()
必须等到 setP
完成(因为它们都是同步的,共享隐式 this
锁),并且由于 this
中的逻辑=14=] 条件不成立。
您的示例过于复杂。可以这样写出来(在两种方法上都加上synchronized,看什么都不打印):
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;
}
}
另请注意,静态同步方法在 Class
对象上进行同步,因为它们没有 this
。因此,实例和静态方法不会相互锁定,除非您在公共锁上显式同步。
只有在以下情况下才会显示输出:
if(x != y)
因为在行中:
p.x = a;
p.y = p.x;
int x = p.x , y = p.y;
你使 x == y 不显示输出。
当您从 s 方法中删除同步关键字时 - 线程有时会将 x 设置为 0,这会使 if(x != y) - 为真。并且输出是可见的。
在 Java 中,所有 synchronized
调用都在一个对象上同步。对于实例方法,它们的对象是 class 实例 - 因此在您的情况下 setP
和 s
都在 IFoo
.
这允许您控制对通过多种方法访问的共享字段的访问。对于您的代码,这正是您所需要的——您需要确保 setP
中没有一个线程正在更改状态,而 s
中的另一个线程正在读取状态。
如果您喜欢更精细的控制,您可以使用同步块,它允许您指定要锁定的对象:
private final Object o=new Object();
public void method(){
synchronized (o){
//Synchronized code
}
}
这是通常的 generally recommended approach - 它允许您封装您的锁,因此您不会冒其他 class 干扰您的锁并可能对您的代码进行 DOS 的风险。
静态方法在 class 对象(例如 IFoo.class
)上同步。