以下名词解释:
顺序执行:先调用的先执行;
随机执行:没有规律,与计算机硬件资源有关,哪个线程先得到资源就先执行,各个线程之间互不干扰
将从以下8个方面介绍锁现象
1. 多个线程使用同一把锁-顺序执行
2. 多个线程使用同一把锁,其中某个线程里面还有阻塞-顺序先执行
3. 多个线程有锁与没锁-随机执行
4.多个线程使用多把锁-随机执行
5. Class锁:多个线程使用一个对象-顺序执行
6. Class锁:多个线程使用多个对象-顺序执行
7. Class锁与对象锁:多个线程使用一个对象-随机执行
8. Class锁与对象锁:多个线程使用多个对象-随机执行
1. 多个线程使用同一把锁-顺序执行
多个线程使用同一个对象,多个线程就是使用一把锁,先调用的先执行!
示例1、 标准访问,请问先打印邮件还是短信?
package com.juc.study.lock8; /** * @ClassName: * @PackageName: com.juc.study.lock8 * @author: youjp * @create: 2020-04-15 16:32 * @description: TODO 示例1.标准访问,请问先打印邮件还是短信? * @Version: 1.0 */ public class Test1 { public static void main(String[] args) { Phone phone = new Phone(); new Thread(() -> { phone.sendEmail(); }, "A").start(); new Thread(() -> { phone.sendMsg(); }, "B").start(); } } class Phone { public synchronized void sendEmail() { System.out.println("发邮件"); } public synchronized void sendMsg() { System.out.println("发短信"); } }
2. 多个线程使用同一把锁,其中某个线程里面还有阻塞-顺序先执行
多个线程使用同一个对象,多个线程就是使用一把锁,先调用的先执行,即使在某方法中设置了阻塞。
示例2、邮件方法暂停4秒钟,请问先打印邮件还是短信?
package com.juc.study.lock8; import java.util.concurrent.TimeUnit; /** * @ClassName: * @PackageName: com.juc.study.lock8 * @author: youjp * @create: 2020-04-15 17:02 * @description: TODO 示例2、邮件方法暂停4秒钟,请问先打印邮件还是短信? * @Version: 1.0 */ public class Test2 { public static void main(String[] args) { Phone2 phone=new Phone2(); new Thread(() -> { phone.sendEmail(); }, "A").start(); new Thread(() -> { phone.sendMsg(); }, "B").start(); } } class Phone2 { public synchronized void sendEmail() { try { TimeUnit.SECONDS.sleep(4); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("发邮件"); } public synchronized void sendMsg() { System.out.println("发短信"); } }
3. 多个线程有锁与没锁-随机执行
多个线程,有的线程有锁,有的线程没锁,两者之间不存在竞争同一把锁的情况,先后执行顺序是随机的。
这种情况犹如你跟你老婆下班回家,家里面的厕所是有锁的,卧室没有锁,俩人到家后,你老婆先上厕所(有锁),你可以一直等待你老婆出来,你再去厕所后,才进卧室,你也可以先进卧室,等你老婆出来后,你再进厕所。
示例3、新增一个普通方法发qq,请问先打印邮件还是接收QQ?
package com.juc.study.lock8; import java.util.concurrent.TimeUnit; /** * @ClassName: * @PackageName: com.juc.study.lock8 * @author: youjp * @create: 2020-04-15 17:02 * @description: TODO 示例3、新增一个普通方法发qq,请问先打印邮件还是接收QQ? * @Version: 1.0 */ public class Test3 { public static void main(String[] args) { Phone3 phone=new Phone3(); new Thread(() -> { phone.sendEmail(); //发邮件 }, "A").start(); new Thread(() -> { phone.sendMsg(); //发短信 }, "B").start(); new Thread(() -> { phone.sendQQ(); //发QQ }, "C").start(); } } class Phone3 { //发邮件 public synchronized void sendEmail() { try { TimeUnit.SECONDS.sleep(4); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("发邮件"); } //发短信 public synchronized void sendMsg() { System.out.println("发短信"); } //发QQ: 新增的方法没有被 synchronized 修饰,不是同步方法,所以不需要等待,其他线程用了一个把锁 public void sendQQ(){ System.out.println("发QQ"); } }
4.多个线程使用多把锁-随机执行
1、被 synchronized 修饰的方法,锁的对象是方法的调用者;
2、调用者不同,它们之间用的不是同一个锁,相互之间没有关系。
示例4、两部手机、请问先打印邮件还是短信?
package com.juc.study.lock8; import java.util.concurrent.TimeUnit; /** * @ClassName: * @PackageName: com.juc.study.lock8 * @author: youjp * @create: 2020-04-15 17:18 * @description: TODO 示例4、两部手机、请问先打印邮件还是短信? * @Version: 1.0 */ public class Test4 { public static void main(String[] args) { Phone4 phoneOne=new Phone4(); Phone4 phoneTwo=new Phone4(); // 两个线程使用的是同一个对象。两个线程是一把锁!先调用的先执行! new Thread(() -> { phoneOne.sendEmail(); }, "A").start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(() -> { phoneTwo.sendMsg(); }, "B").start(); } } class Phone4 { /** * @description: * 被 synchronized 修饰的方法,锁的对象是方法的调用者; * 调用者不同,它们之间用的不是同一个锁,相互之间没有关系。 */ //发邮件 public synchronized void sendEmail() { //善意延迟 try { TimeUnit.SECONDS.sleep(4); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"发邮件"); } //发短信 public synchronized void sendMsg() { System.out.println(Thread.currentThread().getName()+"发短信"); } }
5. Class锁:多个线程使用一个对象-顺序执行
被 synchronized 和 static 同时修饰的方法,锁的对象是类的 class 对象,是唯一的一把锁。线程之间是顺序执行。
锁Class和锁对象的区别:
1、Class 锁 ,类模版,只有一个;
2、对象锁 , 通过类模板可以new 多个对象。
如果全部都锁了Class,那么这个类下的所有对象都具有同一把锁
示例5、两个静态同步方法,同一部手机,请问先打印邮件还是短信?
package com.juc.study.lock8; import java.util.concurrent.TimeUnit; /** * @ClassName: * @PackageName: com.juc.study.lock8 * @author: youjp * @create: 2020-04-15 17:18 * @description: TODO 示例4、两个静态同步方法,同一部手机,请问先打印邮件还是短信?* * @Version: 1.0 */ public class Test5 { public static void main(String[] args) { Phone5 phoneOne=new Phone5(); new Thread(() -> { phoneOne.sendEmail(); }, "A").start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(() -> { phoneOne.sendMsg(); }, "B").start(); } } class Phone5 { /** * @description: *锁Class和锁对象的区别: * 1、锁 Class,类模版,只有一个; * 2、锁 对象,通过 类模板可以new 多个对象. * 如果全部都锁了Class,那么这个类下的所有对象都具有同一把锁。 *被 synchronized 修饰 和 static 修饰的方法,锁的对象是类的 class 对象,是唯一的一把锁。线程之间是顺序执行。 */ //发邮件 public static synchronized void sendEmail() { try { TimeUnit.SECONDS.sleep(4); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"发邮件"); } //发短信 public static synchronized void sendMsg() { System.out.println(Thread.currentThread().getName()+"发短信"); } }
6. Class锁:多个线程使用多个对象-顺序执行
被 synchronized 修饰 和 static 修饰的方法,锁的对象是类的 class 对象,是唯一的一把锁。
Class锁是唯一的,所以多个对象使用的也是同一个Class锁。
示例6、两个静态同步方法,2部手机,请问先打印邮件还是短信?
package com.juc.study.lock8; import java.util.concurrent.TimeUnit; /** * @ClassName: * @PackageName: com.juc.study.lock8 * @author: youjp * @create: 2020-04-15 17:18 * @description: 示例6、两个静态同步方法,2部手机,请问先打印邮件还是短信? * @Version: 1.0 */ public class Test6 { public static void main(String[] args) { Phone6 phone1 = new Phone6(); Phone6 phone2 = new Phone6(); new Thread(() -> { phone1.sendEmail(); }, "A").start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(() -> { phone2.sendMsg(); }, "B").start(); } } class Phone6 { /** * @description: 锁Class和锁对象的区别: * 1、锁 Class,类模版,只有一个; * 2、锁 对象,通过 类模板可以new 多个对象. * 如果全部都锁了Class,那么这个类下的所有对象都具有同一把锁。 * 被 synchronized和static修饰的方法,锁的对象是类的class对象!唯一的同一把锁 */ //发邮件 public static synchronized void sendEmail() { try { TimeUnit.SECONDS.sleep(4); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "发邮件"); } //发短信 public static synchronized void sendMsg() { System.out.println(Thread.currentThread().getName() + "发短信"); } }
7. Class锁与对象锁:多个线程使用一个对象-随机执行
被 synchronized和static修饰的方法,锁的对象是类的class对象!唯一的同一把锁;
只被synchronized修饰的方法,是普通锁(如对象锁),不是Class锁,所以进程之间执行顺序互不干扰。
示例7、一个普通同步方法,一个静态同步方法,同一部手机,请问先打印邮件还是短信?
package com.juc.study.lock8; import java.util.concurrent.TimeUnit; /** * @ClassName: * @PackageName: com.juc.study.lock8 * @author: youjp * @create: 2020-04-15 17:18 * @description: 示例7、一个普通同步方法,一个静态同步方法,同一部手机,请问先打印邮件还是短信? * @Version: 1.0 */ public class Test7 { public static void main(String[] args) { Phone7 phone1 = new Phone7(); new Thread(() -> { phone1.sendEmail(); }, "A").start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(() -> { phone1.sendMsg(); }, "B").start(); } } class Phone7 { //发邮件 :class 锁 public static synchronized void sendEmail() { try { TimeUnit.SECONDS.sleep(4); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "发邮件"); } //发短信:对象锁 public synchronized void sendMsg() { System.out.println(Thread.currentThread().getName() + "发短信"); } }
8. Class锁与对象锁:多个线程使用多个对象-随机执行
被 synchronized和static修饰的方法,锁的对象是类的class对象!唯一的同一把锁;
只被synchronized修饰的方法,是普通锁(如对象锁),不是Class锁,所以进程之间执行顺序互不干扰。
示例8、一个普通同步方法,一个静态同步方法,2部手机,请问先打印邮件还是短信?
package com.juc.study.lock8; import java.util.concurrent.TimeUnit; /** * @ClassName: * @PackageName: com.juc.study.lock8 * @author: youjp * @create: 2020-04-16 10:19 * @description: 示例8、一个普通同步方法,一个静态同步方法,2部手机,请问先打印邮件还是短信? * * @Version: 1.0 */ public class Test8 { public static void main(String[] args) { Phone8 phone1 = new Phone8(); Phone8 phone2 = new Phone8(); new Thread(() -> { phone1.sendEmail(); }, "A").start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(() -> { phone2.sendMsg(); }, "B").start(); } } class Phone8 { //发邮件 :class 锁 public static synchronized void sendEmail() { try { TimeUnit.SECONDS.sleep(4); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "发邮件"); } //发短信:对象锁 public synchronized void sendMsg() { System.out.println(Thread.currentThread().getName() + "发短信"); } }
小结
new this 本身的这个对象,调用者
static class 类模板,保证唯一!
一个对象中有多个 synchronized方法,某个时刻内只要有一个线程去访问 synchronized 方法了就会被加锁,独立公共厕所!其他线程就会阻塞!
加了一个普通方法后两个对象,无关先后,一个有锁,一个没锁!情况会变化!
换成静态同步方法,情况会变化! CLASS ,所有静态同步方法的锁唯一 ,对象实例class 本身!
有兴趣的老爷,可以关注我的公众号【一起收破烂】,回复【006】获取2021最新java面试资料以及简历模型120套哦~