1、标准情况下,两个线程执行,先发短信,然后打电话。
是因为用synchronized修饰方法上的时候,会锁方法的调用者,谁先拿到锁就谁先执行,并且sleep()也不会释放锁。
import java.util.concurrent.TimeUnit;
public class Test1 {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(()->{
phone.sendMsg();
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone.call();
}).start();
}
}
class Phone{
public synchronized void sendMsg(){
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
}
现在加多一个对象,分别执行两条线程
package com.li.lock8;
import org.apache.commons.collections.collection.UnmodifiableCollection;
import java.util.*;
import java.util.concurrent.TimeUnit;
public class Test2 {
public static void main(String[] args) {
// 对象锁
Phone1 phone = new Phone1();
Phone1 phone1 = new Phone1();
new Thread(()->{
phone.sendMsg();
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone1.call();
}).start();
}
}
class Phone1{
public synchronized void sendMsg(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
}
执行结果:一秒后打电话,四秒后发短信
因为是对象锁所以锁的是每个对象。
2、增加两个静态同步方法,只有一个对象
加static修饰后的是类锁,在类加载的时候就有,并且只有唯一一个Class对象,所以也是谁先拿到所谁先执行。
public class Test3 {
public static void main(String[] args) {
Phone3 phone = new Phone3();
new Thread(()->{
phone.sendMsg();
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone.call();
}).start();
}
}
class Phone3{
public static synchronized void sendMsg(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public static synchronized void call(){
System.out.println("打电话");
}
}
执行结果:4秒后发短信,然后立马打电话
现在变成两个对象,分别开启两个线程,结果还是一样,所以类锁只能同时允许一个对象操作,因为Class对象只能存在一个。
3、一个对象,一个静态同步方法,一个普通同步方法
两个不同类型的锁不需要互相等待,可以直接运行。
public class Test4 {
public static void main(String[] args) {
Phone4 phone = new Phone4();
new Thread(()->{
phone.sendMsg();
}).start();
try {
TimeUnit.SECONDS.sleep(1);
System.out.println("等待一秒");
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone.call();
}).start();
}
}
class Phone4{
public static synchronized void sendMsg(){
try {
System.out.println("等待四秒");
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
}
运行结果:一秒后打电话,四秒后发短信。总的来说就是不同类型的锁互不干扰。
总结:
1.类锁是对静态方法使用synchronized关键字后,无论是多线程访问单个对象还是多个对象的sychronized块,都是同步的。
2.对象锁是实例方法使用synchronized关键字后,如果是多个线程访问同个对象的sychronized块,才是同步的,但是访问不同对象的话就是不同步的。
3.类锁和对象锁是两种不同的锁,可以同时使用,但是注意类锁不要嵌套使用,这样子容易发生死锁。