七种情况分析
1、方法都使用synchronized进行修饰,一个 phone 实例
import java.util.concurrent.TimeUnit;
public class SpringBootTestApplicationDemo {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(() ->{
phone.sendMessage();
}, "threadA").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() ->{
phone.callUp();
}, "threadB").start();
}
}
class Phone{
public synchronized void sendMessage(){
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void callUp(){
System.out.println("打电话");
}
}
执行结果:
发短信
打电话结果分析
为什么先是发短信后是打电话?
原因:synchronized 修饰,锁的是当前调用对象,由于 phone 实例对象只有一个,所以哪个线程先拿到锁,哪个线程先执行
2、方法都使用synchronized进行修饰,两个 phone 实例
import java.util.concurrent.TimeUnit;
public class SpringBootTestApplicationDemo {
public static void main(String[] args) {
Phone phone1 = new Phone();
Phone phone2 = new Phone();
new Thread(() ->{
phone1.sendMessage();
}, "threadA").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() ->{
phone2.callUp();
}, "threadB").start();
}
}
class Phone{
public synchronized void sendMessage(){
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void callUp(){
System.out.println("打电话");
}
}
执行结果:
打电话
发短信结果分析
为什么先是发打电话后是发短信?
原因:synchronized 修饰,锁的是当前调用对象,由于 phone 实例对象有两个,不存在竞争锁
3、增加了一个普通方法,没有使用 synchronized 修饰
import java.util.concurrent.TimeUnit;
public class SpringBootTestApplicationDemo {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(() ->{
phone.sendMessage();
}, "threadA").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() ->{
phone.say();
}, "threadB").start();
}
}
class Phone{
public synchronized void sendMessage(){
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void callUp(){
System.out.println("打电话");
}
public void say(){
System.out.println("hello word");
}
}
执行结果:
hello word
发短信结果分析
为什么先是hello word后是发短信?
原因:synchronized 修饰,锁的是当前调用对象,phone 实例对象虽只有一个,但是普通方法的调用,不需要锁
4、两个静态的同步方法,一个对象调用
import java.util.concurrent.TimeUnit;
public class SpringBootTestApplicationDemo {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(() ->{
phone.sendMessage();
}, "threadA").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() ->{
phone.callUp();
}, "threadB").start();
}
}
class Phone{
public static synchronized void sendMessage(){
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public static synchronized void callUp(){
System.out.println("打电话");
}
}
执行结果:
发短信
打电话结果分析
为什么先是发短信后是打电话?
原因:static 和 synchronized 修饰,锁的是当前类 class 实例,由于 class 实例是在类加载时创建(Phone.class),只有一个,所以谁先拿到锁,谁先执行(这里和Phone实例对象无关)
可以换种方式理解,主要是 静态属性 or 方法 随着类加载,在内存中只有一份
Class<?> phone1 = Class.forName("Phone");
Class<Phone> phoneClass = Phone.class;
System.out.println(phone1 == phoneClass);
/**
* 执行结果 true
* class 实例验证
*/
5、两个静态的同步方法,两个对象调用
import java.util.concurrent.TimeUnit;
public class SpringBootTestApplicationDemo {
public static void main(String[] args) {
Phone phone1 = new Phone();
Phone phone2 = new Phone();
new Thread(() ->{
phone1.sendMessage();
}, "threadA").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() ->{
phone2.callUp();
}, "threadB").start();
}
}
class Phone{
public static synchronized void sendMessage(){
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public static synchronized void callUp(){
System.out.println("打电话");
}
}
执行结果:
发短信
打电话结果分析
为什么先是发短信后是打电话?
原因:static 和 synchronized 修饰,锁的是当前类 class 实例,由于 class 实例是在类加载时创建(Phone.class),只有一个,所以谁先拿到锁,谁先执行,这里和多个 Phone 实例无关
6、静态同步方法和普通同步方法,一个对象调用
import java.util.concurrent.TimeUnit;
public class SpringBootTestApplicationDemo {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(() ->{
phone.sendMessage();
}, "threadA").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() ->{
phone.callUp();
}, "threadB").start();
}
}
class Phone{
//静态同步方法
public static synchronized void sendMessage(){
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
//普通同步方法
public synchronized void callUp(){
System.out.println("打电话");
}
}
执行结果:
打电话
发短信结果分析
为什么先是发打电话后是发短信?
原因:普通同步方法 和 静态同步方法锁的对象不同,一个是当前调用者实例,一个是 class实例,它们之间没有关系,不影响相互执行
7、 静态同步方法和普通同步方法,两个对象调用
import java.util.concurrent.TimeUnit;
public class SpringBootTestApplicationDemo {
public static void main(String[] args) {
Phone phone1 = new Phone();
Phone phone2 = new Phone();
new Thread(() ->{
phone1.sendMessage();
}, "threadA").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() ->{
phone2.callUp();
}, "threadB").start();
}
}
class Phone{
//静态同步方法
public static synchronized void sendMessage(){
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
//普通同步方法
public synchronized void callUp(){
System.out.println("打电话");
}
}
执行结果:
打电话
发短信