一、使用
1、几种使用场景
(1)在静态方法中:静态同步方法
(2)在实例方法中:实例同步方法
(3)同步代码块
2、代码演示
//演示synchronized关键字
public class SynchronizedDemo {
//1、静态方法:静态同步方法
public static synchronized void test1(){
}
//同tset1()
public static void test1_2(){
synchronized (SynchronizedDemo.class){
}
}
//2、实例方法:实例同步方法
public synchronized void test2(){
}
//同test2()
public synchronized void test2_2(){
synchronized (this){
}
}
public static void main(String[] args) {
Object o = new Object();
//3、同步代码块
synchronized (o){
}
}
}
二、相关解释
1、synchronized的底层是使用操作系统的mutex lock实现的。
当线程释放锁时,JMM会把该线程对应的工作内存中的共享变量刷新到主内存中
当线程获取锁时,JMM会把该线程对应的本地内存置为无效。从而使得被监视器保护的临界区代码必须从主内存中读取共享变量
synchronized用的锁是存在Java对象头里的
2、对象锁:每个对象都有对象头,包含锁
3、synchronized是获取对象锁的操作
(1)申请对象锁成功
1)持有对象锁,进入代码块
2)执行代码
3)退出代码块,归还对象锁
--- JVM会将竞争失败的线程唤醒
--- 唤醒的线程重新竞争
--- 循环(1)和(2)的逻辑
(2)申请对象锁失败:线程进入下一个同步队列阻塞
1) JVM管理synchronized竞争失败
--- 由运行态转变成阻塞态的方式
--- 将线程放到一个同步队列的数据结构中
--- 对象锁再次可用,将所有竞争该对象锁失败的线程唤醒(阻塞转 变为被唤醒)
4、对象:普通Java对象,类对象
5、注意事项:
(1)只有多个线程对同一个对象申请对象锁时,才会有同步互斥现象
(2)同步互斥:同步代码块,在一个时间点,只有一个线程运行
(3)多个线程竞争不同对象的对象锁时,不会有同步互斥现象
6、静态同步方法 、实例同步方法都可以转换为同步代码块
三、示例
对于以下代码,每两个方法在不同线程中运行时是否会出现同步互斥现象
public class SynchronizedTest {
private Object o = new Object();
private static Object T =SynchronizedDemo.class;
public static synchronized void test1() throws InterruptedException {
Thread.sleep(99999999);
}
public synchronized void test2() throws InterruptedException {
Thread.sleep(99999999);
}
public void test3() throws InterruptedException {
synchronized (o){
Thread.sleep(99999999);
}
}
public void test4() throws InterruptedException {
synchronized (T){
Thread.sleep(99999999);
}
}
}
1、红色格子,由于多个线程使用的都是同一个对象,所以会出现同步互斥现象
2、绿色格子,由于多个线程使用的对象不同,所以不会出现同步互斥现象
3、黄色格子的情况需要根据this对象是否是同一个进行判断
对于test2和test2:
(1)情况一:this对象不是同一个,不会出现同步互斥
//情况1,不会同步互斥
new Thread(() -> {
try {
new SynchronizedTest().test2();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
try {
new SynchronizedTest().test2();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
(2)情况二:this对象是同一个,会出现同步互斥
//情况2,会同步互斥
SynchronizedDemo t =new SynchronizedDemo();
new Thread(() -> {
t.test2();
}).start();
new Thread(() -> {
t.test2();
}).start();
test3和test3同上