synchronized原理
- java中一个对象有且仅有一个同步锁。同步锁依赖对象存在;
- 调用对象的synchronized方法时,就获取了对象的同步锁;
- 不同线程对同步锁的访问时互斥的;
sychronized基本规则
1、当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程对“该对象”的该“synchronized方法”或者“synchronized代码块”
的访问将被阻塞。
public class SynchronizedTest {
public static void main(String[] args) {
SameClassSameSynchronizedBlock thread = new SameClassSameSynchronizedBlock();
Thread thread1 = new Thread(thread,"thread1");
Thread thread2 = new Thread(thread,"thread2");
thread1.start();
thread2.start();
}
}
/**
* 1、已有线程调用类中同步代码块时,另一个线程调用同一个类的同一个同步代码块时,需要等待锁释放
* 注意,若使用继承Thread类的方法来创建线程,在main中实例化两个Thread子类,在此处通过this获取到的同步锁属于两个不同对象,无法使得两个线程互斥
* 若使用实现Runnable接口的方式创建线程,在main中只需实例化一个实现类,故this获取到的同步锁为同一个,可以达到使两个线程互斥的目的
*/
class SameClassSameSynchronizedBlock implements Runnable{
public void run() {
synchronized (this){
try {
for(int i = 0; i < 5; i++){
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + " loop " + i);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
运行结果:
thread1 loop 0
thread1 loop 1
thread1 loop 2
thread1 loop 3
thread1 loop 4
thread2 loop 0
thread2 loop 1
thread2 loop 2
thread2 loop 3
thread2 loop 4
2、当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程仍然可以访问“该对象”的非同步代码块
。
public class SynchronizedTest {
public static void main(String[] args) {
final SameClassNonSynchronizedBlock sameClassNonSynchronizedBlock = new SameClassNonSynchronizedBlock();
Thread thread3 = new Thread(new Runnable() {
public void run() {
sameClassNonSynchronizedBlock.synMethod();
}
}, "thread3");
Thread thread4 = new Thread(new Runnable() {
public void run() {
sameClassNonSynchronizedBlock.nonSynMethod();
}
}, "thread4");
thread3.start();
thread4.start();
}
}
/**
* 2、已有线程调用类中同步代码块时,另一个线程调用同一个类的非同步代码块时,无需等待锁释放
*/
class SameClassNonSynchronizedBlock {
// 含有synchronized同步块的方法
public void synMethod() {
synchronized (this) {
try {
for (int i = 0; i < 5; i++) {
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + " synMethod loop " + i);
}
} catch (InterruptedException ie) {
}
}
}
// 非同步的方法
public void nonSynMethod() {
try {
for (int i = 0; i < 5; i++) {
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + " nonSynMethod loop " + i);
}
} catch (InterruptedException ie) {
}
}
}
运行结果:
thread4 nonSynMethod loop 0
thread3 synMethod loop 0
thread3 synMethod loop 1
thread4 nonSynMethod loop 1
thread3 synMethod loop 2
thread4 nonSynMethod loop 2
thread3 synMethod loop 3
thread4 nonSynMethod loop 3
thread3 synMethod loop 4
thread4 nonSynMethod loop 4
3、 当一个线程访问“某对象”的“synchronized方法”或者“synchronized代码块”时,其他线程对“该对象”的其他的“synchronized方法”或者“synchronized代码块”
的访问将被阻塞。
public class SynchronizedTest {
public static void main(String[] args) {
final SameClassDiffSynchronizedMethod sameClassDiffSynchronizedMethod = new SameClassDiffSynchronizedMethod();
Thread thread5 = new Thread(new Runnable() {
public void run() {
sameClassDiffSynchronizedMethod.synMethod1();
}
}, "thread5");
Thread thread6 = new Thread(new Runnable() {
public void run() {
sameClassDiffSynchronizedMethod.synMethod2();
}
}, "thread6");
thread5.start();
thread6.start();
}
}
class SameClassDiffSynchronizedMethod{
//同步方法1
public synchronized void synMethod1(){
try {
for (int i = 0; i < 5; i++) {
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + " synMethod1 loop " + i);
}
} catch (InterruptedException ie) {
}
}
//同步方法2
public synchronized void synMethod2(){
try {
for (int i = 0; i < 5; i++) {
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + " synMethod2 loop " + i);
}
} catch (InterruptedException ie) {
}
}
}
运行结果:
thread5 synMethod1 loop 0
thread5 synMethod1 loop 1
thread5 synMethod1 loop 2
thread5 synMethod1 loop 3
thread5 synMethod1 loop 4
thread6 synMethod2 loop 0
thread6 synMethod2 loop 1
thread6 synMethod2 loop 2
thread6 synMethod2 loop 3
thread6 synMethod2 loop 4
实例锁和全局锁
实例锁
锁在某一个实例对象上,若该类为单例对象,该锁具有全局性质。实例锁对应synchronized
关键字。
全局锁
该锁针对的是类,无论实例多少个对象,那么线程都共享该锁。全局锁对应static synchronized
(或者是锁在该类的class或者classloader对象上)
eg:
pulbic class Something {
public synchronized void isSyncA(){}
public synchronized void isSyncB(){}
public static synchronized void cSyncA(){}
public static synchronized void cSyncB(){}
}
假设,Something有两个实例x和y。分析下面4组表达式获取的锁的情况。
(01) x.isSyncA()与x.isSyncB()
(02) x.isSyncA()与y.isSyncA()
(03) x.cSyncA()与y.cSyncB()
(04) x.isSyncA()与Something.cSyncA()
- (01) 不能被同时访问。因为isSyncA()和isSyncB()都是访问同一个对象(对象x)的同步锁!
- (02) 可以同时被访问。因为访问的不是同一个对象的同步锁,x.isSyncA()访问的是x的同步锁,而y.isSyncA()访问的是y的同步锁。
- (03) 不能被同时访问。因为cSyncA()和cSyncB()都是static类型,x.cSyncA()相当于Something.isSyncA(),y.cSyncB()相当于Something.isSyncB(),因此它们共用一个同步锁,不能被同时访问。
- (04) 可以被同时访问。因为isSyncA()是实例方法,x.isSyncA()使用的是对象x的锁;而cSyncA()是静态方法,Something.cSyncA()可以理解对使用的是“类的锁”。因此,它们是可以被同时访问的。