我在java中有关于同步的问题。在下面的Java程序中,我没有得到任何输出。但是,如果我从方法IFoo.s()中删除synchronized语句,我将获得一些输出。似乎方法IFoo.setP()和IFoo.s()在彼此之间是同步的。但是'同步'应该只防止两个线程同时调用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;
}
}
}
那么,为什么我看不到任何输出?
问候
答案 0 :(得分:4)
因为同步x != y
永远不会成真。
在您的非同步版本s()
中,偶尔可以将p.x设置为0(即使它未正确同步)。
在同步版本s()
中必须等到setP
完成(因为它们都已同步,共享隐式this
锁定),并且感谢{{1}中的逻辑条件不可能是真的。
你的例子过于复杂。您可以按如下方式编写它(在两种方法上添加同步以查看将不会打印任何内容):
setP
另请注意,静态同步方法在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
。因此,除非您明确地同步公共锁,否则实例和静态方法不会相互锁定。
答案 1 :(得分:3)
在Java中,所有synchronized
调用都在对象上同步。对于实例方法,它们的对象是类实例 - 因此在您的情况下setP
和s
都在IFoo
的实例上同步。
这允许您控制对通过多种方法访问的共享字段的访问。使用您的代码,这正是您所需要的 - 您需要确保setP
中的一个帖子没有更改状态,而s
中的另一个正在读取它。
如果您更喜欢更精细的控制,可以使用synchronized块,它允许您指定要锁定的对象:
private final Object o=new Object();
public void method(){
synchronized (o){
//Synchronized code
}
}
这通常是generally recommended approach - 它允许您封装锁,因此您不会冒一些其他类干扰您的锁并可能使您的代码加密的风险。
静态方法在类对象上同步(例如IFoo.class
)。
答案 2 :(得分:1)
使这些方法同步有两个影响:
首先,对同一对象的两个同步方法的调用不可能进行交错。当一个线程正在执行时 对象的同步方法,所有其他调用的线程 同一对象块的同步方法(暂停执行) 直到第一个线程完成对象。
其次,当同步方法退出时,它会自动建立与之后的任何关系 调用同一对象的同步方法。这个 保证所有人都可以看到对象状态的变化 线程。
答案 3 :(得分:1)
仅在以下情况下显示输出:
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) - 为true。和输出是可见的。
答案 4 :(得分:0)
因为通常你不应该得到任何输出,因为x应该等于y。 但是,当您删除synchronized关键字时,两个线程同时执行,如果s()在p.y = p.x和x = p.x语句之间执行,则可能会得到输出。