学习过程观看视频:[狂神说Java]
https://www.bilibili.com/video/BV1B7411L7tE?p=10
欢迎大家支持噢,很良心的老师了!
现象1:先打印发短信,还是打电话?
java代码
package com.zjl;
import java.util.concurrent.TimeUnit;
/**
* Created by zjl
* 2020/11/20
**/
public class Test4 {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(()->{
phone.sendSms();
},"A").start();
new Thread(()->{
phone.call();
},"B").start();
}
}
class Phone{
public synchronized void sendSms(){
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
}
运行截图
解释:
synchronized锁的是对象的调用者,调用两个方法的都是同一个对象phone,也就是用的同一个锁,当一个方法占用此对象锁时,只有这个方法执行完才会释放锁。
现象2
package com.zjl;
import java.util.concurrent.TimeUnit;
/**
* Created by zjl
* 2020/11/20
**/
public class Test4 {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(()->{
phone.sendSms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
System.out.println("1秒");
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone.call();
},"B").start();
}
}
class Phone{
public synchronized void sendSms(){ //加锁
try {
TimeUnit.SECONDS.sleep(4);
System.out.println("4秒");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){ //加锁
System.out.println("打电话");
}
}
运行截图:
解释:
synchronized锁的是对象的调用者,调用两个方法的都是同一个对象phone,也就是用的同一个锁,当一个方法占用此对象锁时,只有这个方法执行完才会释放锁,也就是先占用锁的先执行完毕,才能其他人占用锁。
现象3:增加一个普通方法,先输出发短信还是hello?
package com.zjl;
import java.util.concurrent.TimeUnit;
/**
* Created by zjl
* 2020/11/20
**/
public class Test5 {
public static void main(String[] args) {
Phone5 phone = new Phone5();
new Thread(()->{
phone.sendSms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
System.out.println("1秒");
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone.hello();
},"B").start();
}
}
class Phone5{
public synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);
System.out.println("4秒");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public void hello(){
System.out.println("hello");
}
}
运行截图:
解释:
hello方法没有用synchronized来修饰,所以phone对象锁被其他线程占用的话,也不影响自身线程的执行。
现象4:两个对象,两个被synchronized修饰的方法,先输出发短信还是打电话?
package com.zjl;
import java.util.concurrent.TimeUnit;
/**
* Created by zjl
* 2020/11/20
**/
public class Test6 {
public static void main(String[] args) {
Phone6 phone1 = new Phone6();
Phone6 phone2 = new Phone6();
new Thread(()->{
phone1.sendSms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
System.out.println("1秒");
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone2.call();
},"B").start();
}
}
class Phone6{
public synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);
System.out.println("4秒");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
}
运行截图:
解释
因为synchronized锁的是方法的调用者,此题中是两个对象,所以两个方法的调用时不受彼此的影响,各自执行各自的,注意,两个地方的线程睡眠,这里看清楚,就明白为什么先打电话,再发短信了。
现象5:一个对象,两个静态方法,先打印发短信,还是打电话?
package com.zjl;
import java.util.concurrent.TimeUnit;
/**
* Created by zjl
* 2020/11/20
**/
public class Test7 {
public static void main(String[] args) {
Phone7 phone1 = new Phone7();
new Thread(()->{
phone1.sendSms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
System.out.println("1秒");
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone1.call();
},"B").start();
}
}
class Phone7{
public static synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);
System.out.println("4秒");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public static synchronized void call(){
System.out.println("打电话");
}
}
执行结果:
解释:
static修饰了的两个synchronized方法,此时锁的并不是方法的调用者phone对象,因为staic静态方法,类一加载就有了,实际上锁的是phone对象的class文件,也就是锁的是phone对象的class模板,而且class模板只有一份,所以执行的时候,先拿到锁的先执行,执行完,其他才能执行。
现象6:两个对象,两个静态同步方法,先打印发短信,还是打电话?
package com.zjl;
import java.util.concurrent.TimeUnit;
/**
* Created by zjl
* 2020/11/20
**/
public class Test7 {
public static void main(String[] args) {
Phone7 phone1 = new Phone7();
Phone7 phone2 = new Phone7();
new Thread(()->{
phone1.sendSms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
System.out.println("1秒");
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone2.call();
},"B").start();
}
}
class Phone7{
public static synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);
System.out.println("4秒");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public static synchronized void call(){
System.out.println("打电话");
}
}
执行结果:
解释:
同现象5解释一致。
static修饰了的两个synchronized方法,此时锁的并不是方法的调用者phone对象,因为staic静态方法,类一加载就有了,实际上锁的是phone对象的class文件,也就是锁的是phone对象的class模板,而且class模板只有一份,所以执行的时候,先拿到锁的先执行,执行完,其他才能执行。
现象7:一个对象,一个静态同步方法,一个普通同步方法,先打印发短信,还是打电话?
package com.zjl;
import java.util.concurrent.TimeUnit;
/**
* Created by zjl
* 2020/11/20
**/
public class Test7 {
public static void main(String[] args) {
Phone7 phone1 = new Phone7();
new Thread(()->{
phone1.sendSms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
System.out.println("1秒");
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone1.call();
},"B").start();
}
}
class Phone7{
public static synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);
System.out.println("4秒");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
}
输出结果:
解释:
synchronized一个锁的是对象,一个锁的是的class类模板,所以两个同步方法锁的并不是同一个东西,所以执行过程中互不影响,注意,两个地方的线程睡眠,这里看清楚,就明白为什么先打电话,再发短信了。
现象8:两个对象,一个静态同步方法,一个普通同步方法,先打印发短信,还是打电话?
package com.zjl;
import java.util.concurrent.TimeUnit;
/**
* Created by zjl
* 2020/11/20
**/
public class Test7 {
public static void main(String[] args) {
Phone7 phone1 = new Phone7();
Phone7 phone2 = new Phone7();
new Thread(()->{
phone1.sendSms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
System.out.println("1秒");
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone2.call();
},"B").start();
}
}
class Phone7{
public static synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);
System.out.println("4秒");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
}
执行结果:
解释:
因为是两个对象,而且一个是静态同步方法,一个是普通同步方法,一个锁的是对象,一个锁的是class模板,所以锁的并不是同一个东西,所以执行过程中互不影响,注意,两个地方的线程睡眠,这里看清楚,就明白为什么先打电话,再发短信了。
小结:
锁的东西无非两种:
1、锁new出来的对象,这种对象是独立的,锁不同对象时是互不影响的。
2、锁class类模板,每个对象类只有一个class类模板。