共计 4509 个字符,预计需要花费 12 分钟才能阅读完成。
synchronized 关键字能够分为对象锁和类锁两个大类。
1. 对象锁
将 synchronized 关键字加载非 static 办法上:
public class testss {public synchronized void minus(){ | |
int count = 5; | |
while (count >= 0){System.out.println(Thread.currentThread().getName() + " " + count); | |
count--; | |
} | |
} | |
} |
测试类:
public class Main {public static void main(String[] args) {testss t = new testss(); | |
new Thread(new Runnable() { | |
@Override | |
public void run() {t.minus(); | |
} | |
}).start(); | |
new Thread(new Runnable() { | |
@Override | |
public void run() {t.minus(); | |
} | |
}).start();} | |
} |
运行后果:
因为调用的办法有 synchronized 关键字的存在,两个线程启动过后按程序运行,程序不会随机产生错乱,然而两个线程哪一个首先开始执行并不一定。
Thread-0 5 | |
Thread-0 4 | |
Thread-0 3 | |
Thread-0 2 | |
Thread-0 1 | |
Thread-0 0 | |
Thread-1 5 | |
Thread-1 4 | |
Thread-1 3 | |
Thread-1 2 | |
Thread-1 1 | |
Thread-1 0 |
咱们批改一下,测试一下当一个线程拜访 synchronized 办法的时候,另一个线程是否拜访其余的 synchronized 办法,咱们增加一个内容一样的 synchronized 办法 minus2(),察看执行后果:
public class testss {public synchronized void minus(){ | |
int count = 5; | |
while (count >= 0){System.out.println(Thread.currentThread().getName() + " " + count); | |
count--; | |
} | |
} | |
public synchronized void minus2(){ | |
int count = 5; | |
while (count >= 0){System.out.println(Thread.currentThread().getName() + " " + count); | |
count--; | |
} | |
} | |
} |
测试类:
public class Main {public static void main(String[] args) {testss t = new testss(); | |
new Thread(new Runnable() { | |
@Override | |
public void run() {t.minus(); | |
} | |
}).start(); | |
new Thread(new Runnable() { | |
@Override | |
public void run() {t.minus2(); | |
} | |
}).start();} | |
} |
测试后果:
Thread-0 5 | |
Thread-0 4 | |
Thread-0 3 | |
Thread-0 2 | |
Thread-0 1 | |
Thread-0 0 | |
Thread-1 5 | |
Thread-1 4 | |
Thread-1 3 | |
Thread-1 2 | |
Thread-1 1 | |
Thread-1 0 |
会发现在一个线程拜访一个对象的 synchronized 办法的时候,另一个线程也不能拜访同一个对象的 synchronized 办法。,这时候如果去掉 minus2() 的 synchronized 关键字,让它变成一个非同步的办法,那么执行的后果又是乱序的。
当初有一个问题就是为什么称增加在非 static 办法后面的 synchronized 关键字为对象锁?咱们看一下代码:
class Mytest {public synchronized void minus(){ | |
int count = 5; | |
while (count > 0){System.out.println(Thread.currentThread().getName() + "1" + count); | |
count--; | |
}; | |
} | |
} | |
public class Main {public static void main(String[] args) throws InterruptedException {final Mytest test = new Mytest(); | |
final Mytest test2 = new Mytest(); | |
Thread thread1 = new Thread(new Runnable() { | |
@Override | |
public void run() {test.minus(); | |
} | |
}); | |
Thread thread2 = new Thread(new Runnable() { | |
@Override | |
public void run() {test2.minus2(); | |
} | |
}); | |
thread1.start(); | |
thread2.start();} | |
} |
这时,咱们设置的是两个不同的实例化对象别离调用类中的同步办法,执行的后果是:
Thread-0 1 5 | |
Thread-1 2 5 | |
Thread-0 1 4 | |
Thread-1 2 4 | |
Thread-0 1 3 | |
Thread-1 2 3 | |
Thread-1 2 2 | |
Thread-1 2 1 | |
Thread-0 1 2 | |
Thread-0 1 1 |
乱序的。
也就阐明了增加在一般办法后面的 synchronized 关键字,只能保障在同一个对象中这个办法是同步的,在不同的对象调用这个办法的时候 synchronized 是无奈影响执行的。这也就是为什么叫对象锁。
2. 类锁
类锁的用法是润饰类中的 static 办法,或者应用代码块,需援用以后的类。
public static synchronized void test(){// TODO} | |
public static void test(){synchronized (TestSynchronized.class) {// TODO} | |
} |
首先类锁在多个过程同时拜访该同步办法的时候成果与对象锁是统一的:
class Mytest {public static synchronized void minus(){ | |
int count = 5; | |
while (count > 0){System.out.println(Thread.currentThread().getName() + "1" + count); | |
count--; | |
}; | |
} | |
} | |
public class Main {public static void main(String[] args) throws InterruptedException {final Mytest test = new Mytest(); | |
Thread thread1 = new Thread(new Runnable() { | |
@Override | |
public void run() {test.minus(); | |
} | |
}); | |
Thread thread2 = new Thread(new Runnable() { | |
@Override | |
public void run() {test.minus(); | |
} | |
}); | |
thread1.start(); | |
thread2.start();} | |
} |
Thread-0 1 5 | |
Thread-0 1 4 | |
Thread-0 1 3 | |
Thread-0 1 2 | |
Thread-0 1 1 | |
Thread-1 1 5 | |
Thread-1 1 4 | |
Thread-1 1 3 | |
Thread-1 1 2 | |
Thread-1 1 1 |
然而当类中有一个类锁,有一个对象锁的时候,成果如何:
class Mytest {public static synchronized void minus(){ | |
int count = 5; | |
while (count > 0){System.out.println(Thread.currentThread().getName() + "1" + count); | |
count--; | |
}; | |
} | |
public synchronized void minus2(){ | |
int count = 5; | |
while (count > 0){System.out.println(Thread.currentThread().getName() + "2" + count); | |
count--; | |
}; | |
} | |
} | |
public class Main {public static void main(String[] args) throws InterruptedException {final Mytest test = new Mytest(); | |
Thread thread1 = new Thread(new Runnable() { | |
@Override | |
public void run() {test.minus(); | |
} | |
}); | |
Thread thread2 = new Thread(new Runnable() { | |
@Override | |
public void run() {test.minus2(); | |
} | |
}); | |
thread1.start(); | |
thread2.start();} | |
} |
后果如下:
Thread-0 1 5 | |
Thread-0 1 4 | |
Thread-1 2 5 | |
Thread-0 1 3 | |
Thread-0 1 2 | |
Thread-0 1 1 | |
Thread-1 2 4 | |
Thread-1 2 3 | |
Thread-1 2 2 | |
Thread-1 2 1 |
因而能够发现对象锁和类锁是互不影响的。
再看看如果应用两个实例对象来调用同一个同步了的静态方法是否会收类锁的影响:
class Mytest {public static synchronized void minus(){ | |
int count = 5; | |
while (count > 0){System.out.println(Thread.currentThread().getName() + "1" + count); | |
count--; | |
}; | |
} | |
} | |
public class Main {public static void main(String[] args) throws InterruptedException {final Mytest test = new Mytest(); | |
final Mytest test2 = new Mytest(); | |
Thread thread1 = new Thread(new Runnable() { | |
@Override | |
public void run() {test.minus(); | |
} | |
}); | |
Thread thread2 = new Thread(new Runnable() { | |
@Override | |
public void run() {test2.minus(); | |
} | |
}); | |
thread1.start(); | |
thread2.start();} | |
} |
后果:
Thread-0 1 5 | |
Thread-0 1 4 | |
Thread-0 1 3 | |
Thread-0 1 2 | |
Thread-0 1 1 | |
Thread-1 1 5 | |
Thread-1 1 4 | |
Thread-1 1 3 | |
Thread-1 1 2 | |
Thread-1 1 1 |
所以类锁是能笼罩到所有实例化这个类的对象的,因而就算应用不同的对象调用类中的同步的 static 办法,还是会受到类锁的影响。
3. 总结
synchronized 关键字用在一般办法上只对以后的对象的这个办法有同步作用。且当一个线程执行同步办法时,其余线程不可拜访该对象的其余同步办法,然而能够拜访不同步的办法。
synchronized 关键字用在 static 办法上对任何实例化这个类的对象均无效。然而不影响对象锁办法的执行。