4.1 标准访问
package cn.guardwhy.test04;
import java.util.concurrent.TimeUnit;
/*
* 标准访问:先发短信还是打电话?
*/
public class LockTest01 {
public static void main(String[] args) {
// 创建phone对象
Phone phone = new Phone();
new Thread(()->{
phone.sendMessage();
}, "curry").start();
try {
// 睡眠1s
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone.call();
}, "kobe").start();
}
}
// 手机类
class Phone{
public synchronized void sendMessage(){
System.out.println("发短信...");
}
public synchronized void call(){
System.out.println("打电话...");
}
}
执行结果
总结
synchronized修饰的方法,锁的对象是方法的调用者。因为两个方法的调用者是同一个,所以当两个方法用的是同一个锁,先调用方法的先执行。
4.2 短信暂停5s
package cn.guardwhy.test04;
import java.util.concurrent.TimeUnit;
/*
* 发短信延迟5s,谁先访问?
*/
public class LockTest01 {
public static void main(String[] args) {
// 创建phone对象
Phone phone = new Phone();
new Thread(()->{
phone.sendMessage();
}, "curry").start();
try {
// 睡眠1s
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone.call();
}, "kobe").start();
}
}
// 手机类
class Phone{
public synchronized void sendMessage(){
try {
// 睡眠5s
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信...");
}
public synchronized void call(){
try {
// 睡眠5s
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("打电话...");
}
}
执行结果
结论:
synchronized修饰的方法,锁的对象是方法的调用者。因为两个方法的调用者是同一个,所以两个方法用的是同一个锁,先调用方法的先执行,第二个方法只有在第一个方法执行完释放锁之后才能执行。
4.3 新增普通方法
package cn.guardwhy.test04;
import java.util.concurrent.TimeUnit;
/*
新增一个普通方法test(),请问先打短信还是test?
*/
public class LockTest02 {
public static void main(String[] args) {
// 创建phone对象
Phone2 phone2 = new Phone2();
new Thread(()->{
phone2.sendMessage();
}, "curry").start();
try {
// 睡眠1s
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone2.test();
}, "kobe").start();
}
}
// 手机类
class Phone2{
public synchronized void sendMessage(){
try {
// 睡眠5s
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信...");
}
public synchronized void call(){
System.out.println("打电话...");
}
// 普通方法
public void test(){
System.out.println("hello world!!!");
}
}
执行结果
总结:
新增的方法没有被synchronized修饰,不是同步方法,不受锁的影响,所以不需要等待。其他线程共用了一把锁,所以还需要等待。
4.4 两个对象
package cn.guardwhy.test04;
import java.util.concurrent.TimeUnit;
/*
两部手机、先call还是sendMessage?
*/
public class LockTest03 {
public static void main(String[] args) {
// 创建phone对象,两个对象,两个调用者,两把锁
Phone3 phone1 = new Phone3();
Phone3 phone2 = new Phone3();
new Thread(()->{
phone1.sendMessage();
}, "curry").start();
try {
// 睡眠1s
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone2.call();
}, "kobe").start();
}
}
// 手机类
class Phone3{
public synchronized void sendMessage(){
try {
// 睡眠5s
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信...");
}
public synchronized void call(){
System.out.println("打电话...");
}
}
执行结果
总结
被synchronized修饰的方法,锁的对象是方法的调用者。因为用了两个对象调用各自的方法,所以两个方法的调用者不是同一个,两个方法用的不是同一个锁,后调用的方法不需要等待先调用的方法。
4.5 静态同步方法(同对象)
package cn.guardwhy.test04;
import java.util.concurrent.TimeUnit;
/*
* 两个静态同步方法,同一部手机,先发短信还是打电话?
*/
public class LockTest04 {
public static void main(String[] args) {
// 创建phone对象
Phone4 phone4 = new Phone4();
new Thread(()->{
phone4.sendMessage();
}, "curry").start();
try {
// 睡眠1s
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone4.call();
}, "kobe").start();
}
}
// Phone4是唯一的class对象
class Phone4{
/*
* synchronized锁的对象是方法的调用者,static是静态方法。
* 静态方法类一加载就有了!!锁的是Class
*/
public static synchronized void sendMessage(){
try {
// 睡眠5s
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信...");
}
public static synchronized void call(){
System.out.println("打电话...");
}
}
执行结果
总结:
被synchronized和static修饰的方法,锁的对象是类的class对象。因为两个同步方法都被static修饰了,所以两个方法用的是同一个锁,后调用的方法需要等待先调用的方法。
4.6 静态同步方法(两对象)
package cn.guardwhy.test04;
import java.util.concurrent.TimeUnit;
/*
* 两个静态同步方法,同一部手机,先发短信还是打电话?
*/
public class LockTest05 {
public static void main(String[] args) {
// 两个对象的Class类模板只有一个,Static,锁的是Class.
Phone5 phone1 = new Phone5();
Phone5 phone2 = new Phone5();
new Thread(()->{
phone1.sendMessage();
}, "curry").start();
try {
// 睡眠1s
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone2.call();
}, "kobe").start();
}
}
// Phone5是唯一的class对象
class Phone5{
/*
* synchronized锁的对象是方法的调用者,static是静态方法。
* 静态方法类一加载就有了!!锁的是Class
*/
public static synchronized void sendMessage(){
try {
// 睡眠5s
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信...");
}
public static synchronized void call(){
System.out.println("打电话...");
}
}
执行结果
总结:
被synchronized和static修饰的方法,锁的对象是类的class对象。因为两个同步方法都被static修饰了,即便用了两个不同的对象调用方法,两个方法用的还是同一个锁,后调用的方法需要等待先调用的方法。
4.7 普通方法和静态方法(同一对象)
package cn.guardwhy.test06;
import java.util.concurrent.TimeUnit;
/*
* 一个普通同步方法,一个静态同步方法,同一个对象,先发短信还是打电话?
*/
public class LockTest01 {
public static void main(String[] args) {
Phone phone1 = new Phone();
new Thread(()->{
phone1.sendMessage();
}, "curry").start();
try {
// 睡眠1s
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone1.call();
}, "kobe").start();
}
}
class Phone{
/*
* synchronized锁的对象是方法的调用者,static是静态方法。
* 静态方法类一加载就有了!!锁的是Class
*/
public static synchronized void sendMessage(){
try {
// 睡眠5s
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信...");
}
public synchronized void call(){
System.out.println("打电话...");
}
}
执行结果
总结:
被synchronized和static修饰的方法,锁的对象是类的class对象。仅仅被synchronized修饰的方法,锁的对象是方法的调用者。因为两个方法锁的对象不是同一个,所以两个方法用的不是同一个锁,后调用的方法不需要等待先调用的方法。
4.8 普通方法和静态方法(两个对象)
package cn.guardwhy.test06;
import java.util.concurrent.TimeUnit;
/*
* 一个普通同步方法,一个静态同步方法,同一个对象,先发短信还是打电话?
*/
public class LockTest01 {
public static void main(String[] args) {
Phone phone1 = new Phone();
Phone phone2 = new Phone();
new Thread(()->{
phone1.sendMessage();
}, "curry").start();
try {
// 睡眠1s
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone2.call();
}, "kobe").start();
}
}
class Phone{
// 静态的同步方法:锁的是Class类模板
public static synchronized void sendMessage(){
try {
// 睡眠5s
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信...");
}
// 普通的同步方法: 锁的是调用者
public synchronized void call(){
System.out.println("打电话...");
}
}
执行结果
总结:
被synchronized和static修饰的方法,锁的对象是类的class对象。仅仅被synchronized修饰的方法,锁的对象是方法的调用者。即便是用同一个对象调用两个方法,锁的对象也不是同一个,所以两个方法用的不是同一个锁,后调用的方法不需要等待先调用的方法。
4.9 八锁现象总结
对于普通同步方法,锁的是当前实例对象。
对于静态同步方法,锁的是当前的Class对象。
对于同步方法块,锁是synchronized括号里面的配置对象。