通过示例说明:(注意代码中的延时问题)
情况1、2
/*
8锁,就是锁的8个问题
1.标准情况下(只有上面的延迟),两个线程先打印发短信还是打电话? 1.发短信 2.打电话 (锁的是同一个对象即方法的调用者,所以是并发)
2.sendSms延迟4秒,两个线程先打印发短信还是打电话? 1.发短信 2.打电话 (锁的是同一个对象即方法的调用者,所以是并发),synchronized 锁的对象是方法的调用者!
*/
public class Test1 {
public static void main(String[] args) {
phone phone = new phone();
//锁的存在
new Thread(()->{
phone.sendSms();
},"A").start();
//捕获
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone.call();
}).start();
}
}
class phone{
// synchronized 锁的对象是方法的调用者!
// 两个方法调用的是同一个锁,谁先拿到谁执行
public synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
}
情况3、4
/*
8锁,就是锁的8个问题
3、hello方法没有synchronized修饰,只有一个对象,则先执行发短信还是hello 1.hello 2.发短信 (hello方法没有锁,不是同步方法,不受锁的影响)
4、,两个对象,则先执行发短信还是打电话 1.打电话 2.发短信 (两个锁的对象不同,是并行,因为延迟可判断是先打电话后发短信)
*/
public class Test2 {
public static void main(String[] args) {
//两个对象,,两个不同的对象,两把锁
phone2 phone1 = new phone2();
phone2 phone2 = new phone2();
//锁的存在
new Thread(()->{
phone1.sendSms();
},"A").start();
//捕获
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone2.call();
},"B").start();
}
}
class phone2{
// synchronized 锁的对象是方法的调用者!
// 两个方法调用的是同一个锁,谁先拿到谁执行
public synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
//这里没有锁,不是同步方法,不受锁的影响
public void hello(){
System.out.println("Hello");
}
}
情况5、6
/*
8锁,就是锁的8个问题
5、增加两个静态的同步方法,只有一个对象,先发短信还是打电话? 1.发短信 2.打电话 (锁的是同一个类对象Class)
6、增加两个静态的同步方法,两个对象,先发短信还是打电话? 1.发短信 2.打电话 (锁的是同一个类对象Class)
*/
public class Test3 {
public static void main(String[] args) {
//两个对象的Class类模板只有一个,static,锁的是Class
phone3 phone1 = new phone3();
phone3 phone2 = new phone3();
//锁的存在
new Thread(()->{
phone1.sendSms();
},"A").start();
//捕获
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone2.call();
},"B").start();
}
}
//phone3只有一个唯一的class对象模板
class phone3{
// synchronized 锁的对象是方法的调用者!
// static 静态方法
// 类一加载就有了,锁的是 Class 类模板
public static synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public static synchronized void call(){
System.out.println("打电话");
}
}
情况7、8
/*
8锁,就是锁的8个问题
7、一个静态同步方法,一个普通同步方法,只有一个对象,先发短信还是打电话? 1.打电话 2.发短信 (锁的并不是同一个对象,静态同步方法锁类模板Class,普通同步方法锁的是方法调用者)
8、一个静态同步方法,一个普通同步方法,两个对象,先发短信还是打电话? 1.打电话 2.发短信 (锁的不是同一个类对象,静态同步方法锁类模板Class,普通同步方法锁的是方法调用者)
*/
public class Test4 {
public static void main(String[] args) {
//两个对象的Class类模板只有一个,static,锁的是Class
phone4 phone1 = new phone4();
phone4 phone2 = new phone4();
//锁的存在
new Thread(()->{
phone1.sendSms();
},"A").start();
//捕获
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone2.call();
},"B").start();
}
}
//phone3只有一个唯一的class对象模板
class phone4{
// synchronized 锁的对象是方法的调用者!
// static 静态方法
// 类一加载就有了,锁的是 Class 类模板
//静态同步方法(锁的是Class类模板)
public static synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
//普通同步方法
//锁的是调用者方法调用者
public synchronized void call(){
System.out.println("打电话");
}
}
总结:
- synchronized的方法被调用时锁的是方法的调用者
- static synchronized 的方法被调用时锁的是Class类的模板(即反射出来的唯一类模板)
- 普通方法 不存在并发问题