我们现在有一个资源类Phone,它有两个基础操作,sendEmail发送邮件和sendMessage发送短信,这两个操作均加上了synchronized锁
问题:
1.标准访问,请问是先打印邮件还是短信?
/**
*
* @ClassName: Phone
* @Description: 手机资源类
* @author: fuling
* @date: 2020年9月10日 下午1:29:17
*/
class Phone{
/**
*
* @Title: sendEmail
* @Description: 发邮件
* @return: void
*/
public synchronized void sendEmail() {
System.out.println("发邮件。。。");
}
/**
*
* @Title: sendMessage
* @Description: 发短信
* @return: void
*/
public synchronized void sendMessage() {
System.out.println("发短信。。。");
}
}
//问题1
public static void ques1() {
Phone phone = new Phone();//一个手机资源
//创建两个线程
//线程A发送邮件
new Thread(()->{
phone.sendEmail();
}, "A").start();
//线程B发送短信
new Thread(()->{
phone.sendMessage();
}, "B").start();
}
执行结果
发邮件。。。
发短信。。。
结果分析
结果是哪个先打印都是有可能的,先执行start()不代表就能先执行,这和操作系统调度的顺序有关
2.邮件方法暂停4秒,请问是先打印邮件还是短信?(我们在创建线程A后先sleep100毫秒让线程A先执行)
/**
*
* @ClassName: Phone
* @Description: 手机资源类
* @author: fuling
* @date: 2020年9月10日 下午1:29:17
*/
class Phone {
/**
*
* @Title: sendEmail
* @Description: 发邮件
* @return: void
*/
public synchronized void sendEmail() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("发邮件。。。");
}
/**
*
* @Title: sendMessage
* @Description: 发短信
* @return: void
*/
public synchronized void sendMessage() {
System.out.println("发短信。。。");
}
}
// 问题2
public static void ques2() {
Phone phone = new Phone();// 一个手机资源
// 创建两个线程
// 线程A发送邮件
new Thread(() -> {
phone.sendEmail();
}, "A").start();
// 休眠100毫秒,保证线程A先得到锁
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 线程B发送短信
new Thread(() -> {
phone.sendMessage();
}, "B").start();
}
执行结果
等待大约4秒后显示以下两行结果
发邮件。。。
发短信。。。
结果分析
A线程先抢到这个手机资源的锁,其抢到锁后立刻睡眠4秒,而sleep是一个只释放cpu时间片而不释放所持有锁的方法,所以A线程是一边“睡着”,一边紧握着锁不让其他线程访问这个手机资源里的同步操作,等待4秒后A线程醒过来,继续发邮件,发完后释放锁,B线程得到锁,打印出发短信
3.新增一个普通方法hello(),请问是先打印邮件还是hello?
/**
*
* @ClassName: Phone
* @Description: 手机资源类
* @author: fuling
* @date: 2020年9月10日 下午1:29:17
*/
class Phone {
/**
*
* @Title: sendEmail
* @Description: 发邮件
* @return: void
*/
public synchronized void sendEmail() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("发邮件。。。");
}
/**
*
* @Title: sendMessage
* @Description: 发短信
* @return: void
*/
public synchronized void sendMessage() {
System.out.println("发短信。。。");
}
//普通方法,不加锁
public void hello() {
System.out.println("hello。。。");
}
}
// 问题3
public static void ques3() {
Phone phone = new Phone();// 一个手机资源
// 创建两个线程
// 线程A发送邮件
new Thread(() -> {
phone.sendEmail();
}, "A").start();
// 休眠100毫秒,保证线程A先得到锁
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 线程B执行普通方法hello
new Thread(() -> {
phone.hello();
}, "B").start();
}
执行结果
先打印hello,大约隔4秒后打印发邮件
hello。。。
发邮件。。。
结果分析
锁只能锁住资源的同步方法,hello是普通方法,所以即使A线程先得到了锁,也不能阻止B线程访问hello方法。因此A线程得到锁后先睡眠4秒钟,期间B线程访问hello,4秒后A线程苏醒,打印发邮件
4.两个Phone资源类,请问是先打印邮件还是短信?
/**
*
* @ClassName: Phone
* @Description: 手机资源类
* @author: fuling
* @date: 2020年9月10日 下午1:29:17
*/
class Phone {
/**
*
* @Title: sendEmail
* @Description: 发邮件
* @return: void
*/
public synchronized void sendEmail() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("发邮件。。。");
}
/**
*
* @Title: sendMessage
* @Description: 发短信
* @return: void
*/
public synchronized void sendMessage() {
System.out.println("发短信。。。");
}
}
// 问题4
public static void ques4() {
// 两个手机资源
Phone phone1 = new Phone();
Phone phone2 = new Phone();
// 创建两个线程
// 线程A使用手机1发送邮件
new Thread(() -> {
phone1.sendEmail();
}, "A").start();
// 休眠100毫秒,保证线程A先得到锁
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 线程B使用手机2发送短信
new Thread(() -> {
phone2.sendMessage();
}, "B").start();
}
执行结果
先打印发短信,大约隔4秒后打印发邮件
发短信。。。
发邮件。。。
结果分析
两个类就拥有两把不同的对象锁,线程A使用资源1发邮件,不影响线程B使用资源2发短信
5.把两个基本操作改为静态同步方法,同一个Phone资源,请问是先打印邮件还是短信?
/**
*
* @ClassName: Phone
* @Description: 手机资源类
* @author: fuling
* @date: 2020年9月10日 下午1:29:17
*/
class Phone {
/**
*
* @Title: sendEmail
* @Description: 发邮件
* @return: void
*/
public static synchronized void sendEmail() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("发邮件。。。");
}
/**
*
* @Title: sendMessage
* @Description: 发短信
* @return: void
*/
public static synchronized void sendMessage() {
System.out.println("发短信。。。");
}
}
// 问题5
public static void ques5() {
// 一个手机资源
Phone phone = new Phone();
// 创建两个线程
// 线程A使用手机发送邮件
new Thread(() -> {
phone.sendEmail();
}, "A").start();
// 休眠100毫秒,保证线程A先得到锁
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 线程B使用手机发送短信
new Thread(() -> {
phone.sendMessage();
}, "B").start();
}
执行结果
等待大约4秒后显示以下两行结果
发邮件。。。
发短信。。。
结果分析
静态同步方法锁住的是类而不是对象,发短信和发邮件在一个资源类里,共享同一把类锁,线程A先抢占到这把类锁,并执行sleep,不释放锁,等到4秒后继续发邮件,释放锁后线程B才能发短信
6.两个基本操作为静态同步方法,两个Phone资源,请问是先打印邮件还是短信?
/**
*
* @ClassName: Phone
* @Description: 手机资源类
* @author: fuling
* @date: 2020年9月10日 下午1:29:17
*/
class Phone {
/**
*
* @Title: sendEmail
* @Description: 发邮件
* @return: void
*/
public static synchronized void sendEmail() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("发邮件。。。");
}
/**
*
* @Title: sendMessage
* @Description: 发短信
* @return: void
*/
public static synchronized void sendMessage() {
System.out.println("发短信。。。");
}
}
//问题6
public static void ques6() {
// 两个手机资源
Phone phone1 = new Phone();
Phone phone2 = new Phone();
// 创建两个线程
// 线程A使用手机1发送邮件
new Thread(() -> {
phone1.sendEmail();
}, "A").start();
// 休眠100毫秒,保证线程A先得到锁
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 线程B使用手机2发送短信
new Thread(() -> {
phone2.sendMessage();
}, "B").start();
}
执行结果
等待大约4秒后显示以下两行结果
发邮件。。。
发短信。。。
结果分析
类锁与资源对象的多少无关,多个资源对象共享一个类锁
7.发邮件为普通同步方法,发短信为静态同步方法,一个Phone资源,请问是先打印邮件还是短信?
/**
*
* @ClassName: Phone
* @Description: 手机资源类
* @author: fuling
* @date: 2020年9月10日 下午1:29:17
*/
class Phone {
/**
*
* @Title: sendEmail
* @Description: 发邮件
* @return: void
*/
public synchronized void sendEmail() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("发邮件。。。");
}
/**
*
* @Title: sendMessage
* @Description: 发短信
* @return: void
*/
public static synchronized void sendMessage() {
System.out.println("发短信。。。");
}
}
// 问题7
public static void ques7() {
// 一个手机资源
Phone phone = new Phone();
// 创建两个线程
// 线程A使用手机发送邮件
new Thread(() -> {
phone.sendEmail();
}, "A").start();
// 休眠100毫秒,保证线程A先得到锁
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 线程B使用手机发送短信
new Thread(() -> {
phone.sendMessage();
}, "B").start();
}
执行结果
先打印发短信,大约隔4秒后打印发邮件
发短信。。。
发邮件。。。
结果分析
发邮件方法带的锁为对象锁,发短信带的锁为类锁,两把锁互不干扰
8.发邮件为普通同步方法,发短信为静态同步方法,两个Phone资源,请问是先打印邮件还是短信?
/**
*
* @ClassName: Phone
* @Description: 手机资源类
* @author: fuling
* @date: 2020年9月10日 下午1:29:17
*/
class Phone {
/**
*
* @Title: sendEmail
* @Description: 发邮件
* @return: void
*/
public synchronized void sendEmail() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("发邮件。。。");
}
/**
*
* @Title: sendMessage
* @Description: 发短信
* @return: void
*/
public static synchronized void sendMessage() {
System.out.println("发短信。。。");
}
}
// 问题8
public static void ques8() {
// 两个手机资源
Phone phone1 = new Phone();
Phone phone2 = new Phone();
// 创建两个线程
// 线程A使用手机1发送邮件
new Thread(() -> {
phone1.sendEmail();
}, "A").start();
// 休眠100毫秒,保证线程A先得到锁
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 线程B使用手机2发送短信
new Thread(() -> {
phone2.sendMessage();
}, "B").start();
}
执行结果
先打印发短信,大约隔4秒后打印发邮件
发短信。。。
发邮件。。。
结果分析
发邮件方法带的锁为对象锁,发短信带的锁为类锁,两把锁互不干扰
总结
解决这类问有主要有两点需要注意
1.sleep只释放cpu时间片,不释放其占用的锁,wait既释放cpu时间片又释放其占用的锁
2.根据锁住的东西不同,可以分为对象锁和类锁,不同类型的锁互不干扰,不是同一把锁也互不干扰