1.Synchronized修饰非静态方法,其实是对调用该方法的对象加锁,俗称“对象锁”。java
Java中每一个对象都有一个锁,而且是惟一的。假设分配的一个对象空间,里面有多个方法,至关于空间里面有多个小房间,若是咱们把全部的小房间都加锁,由于这个对象只有一把钥匙,所以同一时间只能有一我的打开一个小房间,而后用完了还回去,再由JVM 去分配下一个得到钥匙的人。编程
状况1:同一个对象在两个线程中分别访问该对象的两个同步方法安全
结果:会产生互斥。并发
解释:由于锁针对的是对象,当对象调用一个synchronized方法时,其余同步方法须要等待其执行结束并释放锁后才能执行。ide
状况2:不一样对象在两个线程中调用同一个同步方法测试
结果:不会产生互斥。.net
解释:由于是两个对象,锁针对的是对象,并非方法,因此能够并发执行,不会互斥。形象的来讲就是由于咱们每一个线程在调用方法的时候都是new 一个对象,那么就会出现两个空间,两把钥匙,线程
2.Synchronized修饰静态方法,其实是对该类对象加锁,俗称“类锁”。对象
状况1:用类直接在两个线程中调用两个不一样的同步方法blog
结果:会产生互斥。
解释:由于对静态对象加锁实际上对类(.class)加锁,类对象只有一个,能够理解为任什么时候候都只有一个空间,里面有N个房间,一把锁,所以房间(同步方法)之间必定是互斥的。
注:上述状况和用单例模式声明一个对象来调用非静态方法的状况是同样的,由于永远就只有这一个对象。因此访问同步方法之间必定是互斥的。
状况2:用一个类的静态对象在两个线程中调用静态方法或非静态方法
结果:会产生互斥。
解释:由于是一个对象调用,同上。
状况3:一个对象在两个线程中分别调用一个静态同步方法和一个非静态同步方法
结果:不会产生互斥。
解释:由于虽然是一个对象调用,可是两个方法的锁类型不一样,调用的静态方法其实是类对象在调用,即这两个方法产生的并非同一个对象锁,所以不会互斥,会并发执行。
测试代码:
同步方法类:SynchronizedTest.java
public class SynchronizedTest {
/*private SynchronizedTest(){}
private static SynchronizedTest st; //懒汉式单例模式,线程不安全,须要加synchronized同步
public static SynchronizedTest getInstance(){
if(st == null){
st = new SynchronizedTest();
}
return st;
}*/
/*private SynchronizedTest(){}
private static final SynchronizedTest st = new SynchronizedTest(); //饿汉式单利模式,天生线程安全
public static SynchronizedTest getInstance(){
return st;
}*/
public static SynchronizedTest staticIn = new SynchronizedTest(); //静态对象
public synchronized void method1(){ //非静态方法1
for(int i = 0;i < 10;i++){
System.out.println("method1 is running!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public synchronized void method2(){ //非静态方法2
for( int i = 0; i < 10 ; i++){
System.out.println("method2 is running!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public synchronized static void staticMethod1(){ //静态方法1
for( int i = 0; i < 10 ; i++){
System.out.println("static method1 is running!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public synchronized static void staticMethod2(){ //静态方法2
for( int i = 0; i < 10 ; i++){
System.out.println("static method2 is running!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
线程类1:Thread1.java(释放不一样的注释能够测试不一样的状况)
public class Thread1 implements Runnable{
@Override
public void run() {
// SynchronizedTest s = SynchronizedTest.getInstance();
// s.method1();
// SynchronizedTest s1 = new SynchronizedTest();
// s1.method1();
SynchronizedTest.staticIn.method1();
// SynchronizedTest.staticMethod1();
// SynchronizedTest.staticMethod2();
}
}
线程类2:Thread2.Java
public class Thread2 implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
// SynchronizedTest s = SynchronizedTest.getInstance();
// SynchronizedTest s2 = new SynchronizedTest();
// s2.method1();
// s.method2();
// SynchronizedTest.staticMethod1();
// SynchronizedTest.staticMethod2();
// SynchronizedTest.staticIn.method2();
SynchronizedTest.staticIn.staticMethod1();
}
}
主类:ThreadMain.java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadMain {
public static void main(String[] args) {
Thread t1 = new Thread(new Thread1());
Thread t2 = new Thread(new Thread2());
ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(t1);
exec.execute(t2);
exec.shutdown();
}
}
总结:
1.对象锁钥匙只能有一把才能互斥,才能保证共享变量的惟一性
2.在静态方法上的锁,和 实例方法上的锁,默认不是一样的,若是同步须要制定两把锁同样。
3.关于同一个类的方法上的锁,来自于调用该方法的对象,若是调用该方法的对象是相同的,那么锁必然相同,不然就不相同。好比 new A().x() 和 new A().x(),对象不一样,锁不一样,若是A的单利的,就能互斥。
4.静态方法加锁,能和全部其余静态方法加锁的 进行互斥