8锁现象彻底理解锁
Test1
package lock8;
import java.util.concurrent.TimeUnit;
public class Test1 {
public static void main(String[] args) throws InterruptedException {
Data data = new Data();
new Thread(data::SendSMS).start();
TimeUnit.SECONDS.sleep(1);
new Thread(data::SendEmail).start();
}
}
class Data {
public synchronized void SendSMS() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("发短信");
}
public synchronized void SendEmail() {
System.out.println("发邮件");
}
}
会先打印哪个?
先打印发短信,是因为我们中间停了一秒吗,那我们在方法体里停四秒试试:
public synchronized void SendSMS() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("发短信");
}
结果依然是先发短信。
synchronized锁的是对象的调用者
而我们两个方法都是一个对象对象调用的,所以只要一个拿到了锁,另一个只能排队。
Test2
我们加一个普通方法试试呢?
package lock8;
import java.util.concurrent.TimeUnit;
public class Test2 {
public static void main(String[] args) throws InterruptedException {
Data2 data = new Data2();
new Thread(data::SendSMS).start();
TimeUnit.SECONDS.sleep(1);
new Thread(data::Hello).start();
}
}
class Data2 {
public synchronized void SendSMS() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("发短信");
}
public synchronized void SendEmail() {
System.out.println("发邮件");
}
public void Hello() {
System.out.println("Hello");
}
}
普通方法不受锁的影响!
我们再创建一个对象呢?
package lock8;
import java.util.concurrent.TimeUnit;
public class Test2 {
public static void main(String[] args) throws InterruptedException {
Data2 data = new Data2();
Data2 data2 = new Data2();
new Thread(data::SendSMS).start();
TimeUnit.SECONDS.sleep(1);
new Thread(data2::SendEmail).start();
}
}
class Data2 {
public synchronized void SendSMS() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("发短信");
}
public synchronized void SendEmail() {
System.out.println("发邮件");
}
}
两个对象两把锁,在第一个线程拿到锁sleep之后,第二个线程不需要等待。
Test3
那么其余不变,我们把方法改为static之后呢?
package lock8;
import java.util.concurrent.TimeUnit;
public class Test3 {
public static void main(String[] args) throws InterruptedException {
Data3 data = new Data3();
Data3 data2 = new Data3();
new Thread(() -> data.SendSMS()).start();
TimeUnit.SECONDS.sleep(1);
new Thread(() -> data2.SendEmail()).start();
}
}
class Data3 {
public static synchronized void SendSMS() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("发短信");
}
public static synchronized void SendEmail() {
System.out.println("发邮件");
}
}
static方法在类一加载就有了,所以不论创建多少个实例,锁只有一把!就是.Class
Test4
一个静态同步方法,一个非静态同步方法
package lock8;
import java.util.concurrent.TimeUnit;
public class Test4 {
public static void main(String[] args) throws InterruptedException {
Data4 data = new Data4();
Data4 data2 = new Data4();
new Thread(() -> data.SendSMS()).start();
TimeUnit.SECONDS.sleep(1);
new Thread(data2::SendEmail).start();
}
}
class Data4 {
public static synchronized void SendSMS() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("发短信");
}
public synchronized void SendEmail() {
System.out.println("发邮件");
}
}
因为这是两把锁!互不干扰。
总结
锁的对象无非就两种:
一个是具体的实例对象,可以有多把;
一个是static,类模板对象,只有一把。