Synchronized的使用比较简单,就是对代码进行同步。但是昨天在看书的时候发现了一个比较困惑的地方,就是类和实例对象之间的同步。有以下几种情况
1.静态方法间的同步即对类对象进行同步,线程对test1和test2方法的访问是互斥的
static synchronized void test1() {
System.out.println(" test1");
}
static synchronized void test2() {
System.out.println(" test2");
}
2.实例方法间的同步即对实例对象进行同步,线程对同一对象的test1和test2方法的访问是互斥的,但是不同实例对象各自调用的话由于锁住的不同的实例对象,所以test1和test2是不互斥的。
public static void main(String[] args) {
// TODO Auto-generated method stub
ExecutorService pool = Executors.newFixedThreadPool(2);
TestSynchronized test = new TestSynchronized();
pool.execute(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
//test.test1(); //互斥
new TestSynchronized().test1(); //不互斥 因为锁加在不同的实例对象上
}
});
pool.execute(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
//TestSynchronized.test2();
//test.test2(); //互斥
new TestSynchronized().test2();//不互斥,锁加在不同的对象上
}
});
pool.shutdown();
}
synchronized void test1() {
System.out.println(" test1");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
synchronized void test2() {
System.out.println(" test2");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
以上都比较好理解,但是如果是下面这种情况,会怎么样呢?静态方法会和实例方法互斥吗?
public static void main(String[] args) {
// TODO Auto-generated method stub
ExecutorService pool = Executors.newFixedThreadPool(2);
TestSynchronized test = new TestSynchronized();
pool.execute(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
TestSynchronized.test1();
}
});
pool.execute(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
test.test2();
}
});
pool.shutdown();
}
synchronized void test1() {
System.out.println(" test1");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
void test2() {
System.out.println(" test2");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//程序会同时输出test1和test2
答案是不会的,程序会同时输出test1和test2,我的理解是静态方法调用时候锁住的是类对象,也就是存在方法区中的那个,而实例方法调用时候锁住的是实例对象本身,二者并不存在互斥关系。
所以说如果锁住的是类对象,也就是调用静态同步方法或者是synchronized(类.class)同步块的时候,那么有关类对象的同步调用就存在互斥关系,如果锁住的是同一个实例对象,也就是调用同一实例对象的同步方法或者synchronized(this)同步块的时候,则同一实例对象的同步调用存在互斥关系。类对象的同步和实例对象的同步由于锁的是不同对象,所以不存在互斥关系。