本文介绍了synchronized关键字,并给出了对象锁,类锁的案例以及对书中死锁案例的分析。
synchronized关键字是java中的一个关键字,是一种同步锁,而其实现的基础就是java中的每一个对象都可以作为锁。
表现形式如下:
package com.thread;
/**
* 同步测试
*
* @author ez4sterben
* @date 2023/07/24
*/
public class SyncTest {
public static void main(String[] args) {
SyncMethod syncMethod1 = new SyncMethod();
SyncMethod syncMethod2 = new SyncMethod();
Thread thread1 = new Thread(){
@Override
public void run() {
try {
syncMethod1.syncMethod();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
};
Thread thread2 = new Thread(){
@Override
public void run() {
try {
syncMethod2.syncMethod();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
};
thread1.start();
thread2.start();
}
}
class SyncMethod{
public synchronized void syncMethod() throws InterruptedException {
System.out.println("syncMethod开始执行");
System.out.println(System.currentTimeMillis() + " - syncMethod");
Thread.sleep(1000);
System.out.println("syncMethod执行完毕");
}
}
输出结果
syncMethod开始执行
syncMethod开始执行
1690183653777 - syncMethod
1690183653777 - syncMethod
syncMethod执行完毕
syncMethod执行完毕
稍作改动,我们让thread1与thread2争抢对象syncMethod1
Thread thread2 = new Thread(){
@Override
public void run() {
try {
syncMethod1.syncMethod();
syncMethod2.syncMethod();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
};
输出结果如下
syncMethod开始执行
1690183794778 - syncMethod
syncMethod执行完毕
syncMethod开始执行
1690183795793 - syncMethod
syncMethod执行完毕
syncMethod开始执行
1690183796796 - syncMethod
syncMethod执行完毕
因为两个线程争抢syncMethod1对象,我们的调用的方法是带有synchronized关键字的普通方法,这样会锁住对象导致没有拿到锁的线程阻塞,在方法执行完拿到锁后再执行。
package com.thread;
/**
* 同步测试
*
* @author ez4sterben
* @date 2023/07/24
*/
public class SyncTest {
public static void main(String[] args) {
SyncMethod syncMethod1 = new SyncMethod();
SyncMethod syncMethod2 = new SyncMethod();
Thread thread1 = new Thread(){
@Override
public void run() {
try {
SyncMethod.staticSyncMethod();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
};
Thread thread2 = new Thread(){
@Override
public void run() {
try {
SyncMethod.staticSyncMethod();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
};
thread1.start();
thread2.start();
}
}
class SyncMethod{
public synchronized void syncMethod() throws InterruptedException {
System.out.println("syncMethod开始执行");
System.out.println(System.currentTimeMillis() + " - syncMethod");
Thread.sleep(1000);
System.out.println("syncMethod执行完毕");
}
public synchronized static void staticSyncMethod() throws InterruptedException {
System.out.println("staticSyncMethod开始执行");
System.out.println(System.currentTimeMillis() + " - staticSyncMethod");
Thread.sleep(1000);
System.out.println("staticSyncMethod执行完毕");
}
}
结果如下:
staticSyncMethod开始执行
1690184362260 - staticSyncMethod
staticSyncMethod执行完毕
staticSyncMethod开始执行
1690184363261 - staticSyncMethod
staticSyncMethod执行完毕
对代码作出修改,创建一个新的静态同步方法,两个线程分别调用不同的静态同步方法
package com.thread;
/**
* 同步测试
*
* @author ez4sterben
* @date 2023/07/24
*/
public class SyncTest {
public static void main(String[] args) {
SyncMethod syncMethod1 = new SyncMethod();
SyncMethod syncMethod2 = new SyncMethod();
Thread thread1 = new Thread(){
@Override
public void run() {
try {
SyncMethod.staticSyncMethod();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
};
Thread thread2 = new Thread(){
@Override
public void run() {
try {
SyncMethod.staticSyncMethod2();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
};
thread1.start();
thread2.start();
}
}
class SyncMethod{
public synchronized void syncMethod() throws InterruptedException {
System.out.println("syncMethod开始执行");
System.out.println(System.currentTimeMillis() + " - syncMethod");
Thread.sleep(1000);
System.out.println("syncMethod执行完毕");
}
public synchronized static void staticSyncMethod() throws InterruptedException {
System.out.println("staticSyncMethod开始执行");
System.out.println(System.currentTimeMillis() + " - staticSyncMethod");
Thread.sleep(1000);
System.out.println("staticSyncMethod执行完毕");
}
public synchronized static void staticSyncMethod2() throws InterruptedException {
System.out.println("staticSyncMethod2开始执行");
System.out.println(System.currentTimeMillis() + " - staticSyncMethod2");
Thread.sleep(1000);
System.out.println("staticSyncMethod2执行完毕");
}
}
结果如下
staticSyncMethod2开始执行
1690184559625 - staticSyncMethod2
staticSyncMethod2执行完毕
staticSyncMethod开始执行
1690184560628 - staticSyncMethod
staticSyncMethod执行完毕
可以看出,整个类中的静态同步方法无法被同时调用,有线程拿到类锁,其他线程就要进入阻塞状态等待类锁。
再对代码作出修改,我们开启三个线程同时调用同步方法以及静态同步方法。
SyncMethod syncMethod1 = new SyncMethod();
SyncMethod syncMethod2 = new SyncMethod();
Thread thread1 = new Thread(){
@Override
public void run() {
try {
syncMethod1.syncMethod();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
};
Thread thread2 = new Thread(){
@Override
public void run() {
try {
SyncMethod.staticSyncMethod();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
};
Thread thread3 = new Thread(){
@Override
public void run() {
try {
syncMethod1.syncMethod();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
};
thread1.start();
thread2.start();
thread3.start();
syncMethod开始执行
staticSyncMethod开始执行
1690184465603 - staticSyncMethod
1690184465603 - syncMethod
staticSyncMethod执行完毕
syncMethod执行完毕
syncMethod开始执行
1690184466613 - syncMethod
syncMethod执行完毕
从这里我们可以发现,对象锁与类锁其实并不是互斥的,二者可以同时生效
这里的案例我们使用书中的死锁案例
public class DeadLockDemo {
private static String A = "A";
private static String B = "B";
public static void main(String[] args) {
new DeadLockDemo().deadLock();
}
private void deadLock() {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (A) {
try {
Thread.currentThread().sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (B) {
System.out.println("1");
}
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (B) {
synchronized (A) {
System.out.println("2");
}
}
}
});
t1.start();
t2.start();
}
}
t1线程锁住A后让线程沉睡2s,假设cpu分配了30ms的时间片,t1线程显然无法执行完,这时时间片分配给t2线程,t2对B进行加锁并尝试对A加锁,但此时A已经被t1线程锁住,t2线程只能进行等待,直到t1线程执行完,但当t1线程执行完后尝试对B进行加锁,此时B已经被t2锁住,发生死锁。