当前位置: 首页 > news >正文

c 网站开发调试东莞制作企业网站公司

c 网站开发调试,东莞制作企业网站公司,广东南方通信建设有限公司官方网站,沧州模板建站平台blog.csdn.net/x541211190/article/details/106272922简介本文将介绍8种同步方法的访问场景#xff0c;我们来看看这8种情况下#xff0c;多线程访问同步方法是否还是线程安全的。这些场景是多线程编程中经常遇到的#xff0c;而且也是面试时高频被问到的问题#xff0c;所… blog.csdn.net/x541211190/article/details/106272922简介本文将介绍8种同步方法的访问场景我们来看看这8种情况下多线程访问同步方法是否还是线程安全的。这些场景是多线程编程中经常遇到的而且也是面试时高频被问到的问题所以不管是理论还是实践这些都是多线程场景必须要掌握的场景。八种使用场景接下来我们来通过代码实现分别判断以下场景是不是线程安全的以及原因是什么。两个线程同时访问同一个对象的同步方法两个线程同时访问两个对象的同步方法两个线程同时访问一个或两个对象的静态同步方法两个线程分别同时访问一个或两个对象的同步方法和非同步方法两个线程访问同一个对象中的同步方法同步方法又调用一个非同步方法两个线程同时访问同一个对象的不同的同步方法两个线程分别同时访问静态synchronized和非静态synchronized方法同步方法抛出异常后JVM会自动释放锁的情况场景一两个线程同时访问同一个对象的同步方法分析这种情况是经典的对象锁中的方法锁两个线程争夺同一个对象锁所以会相互等待是线程安全的。「两个线程同时访问同一个对象的同步方法是线程安全的。」场景二两个线程同时访问两个对象的同步方法这种场景就是对象锁失效的场景原因出在访问的是两个对象的同步方法那么这两个线程分别持有的两个线程的锁所以是互相不会受限的。加锁的目的是为了让多个线程竞争同一把锁而这种情况多个线程之间不再竞争同一把锁而是分别持有一把锁所以我们的结论是「两个线程同时访问两个对象的同步方法是线程不安全的。」代码验证public class Condition2 implements Runnable {  // 创建两个不同的对象  static Condition2 instance1  new Condition2();  static Condition2 instance2  new Condition2();  Override  public void run() {  method();  }  private synchronized void method() {  System.out.println(线程名  Thread.currentThread().getName()  运行开始);  try {  Thread.sleep(4000);  } catch (InterruptedException e) {  e.printStackTrace();  }  System.out.println(线程  Thread.currentThread().getName()  运行结束);  }  public static void main(String[] args) {  Thread thread1  new Thread(instance1);  Thread thread2  new Thread(instance2);  thread1.start();  thread2.start();  while (thread1.isAlive() || thread2.isAlive()) {  }  System.out.println(测试结束);  }   }  运行结果两个线程是并行执行的所以线程不安全。线程名Thread-0运行开始   线程名Thread-1运行开始   线程Thread-0运行结束   线程Thread-1运行结束   测试结束  代码分析「问题在此」两个线程thread1、thread2访问两个对象instance1、instance2的同步方法method(),两个线程都有各自的锁不能形成两个线程竞争一把锁的局势所以这时synchronized修饰的方法method()和不用synchronized修饰的效果一样不信去把synchronized关键字去掉运行结果一样所以此时的method()只是个普通方法。「如何解决这个问题」若要使锁生效只需将method()方法用static修饰这样就形成了类锁多个实例instance1、instance2共同竞争一把类锁就可以使两个线程串行执行了。这也就是下一个场景要讲的内容。场景三两个线程同时访问一个或两个对象的静态同步方法这个场景解决的是场景二中出现的线程不安全问题即用类锁实现「两个线程同时访问一个或两个对象的静态同步方法是线程安全的。」场景四两个线程分别同时访问一个或两个对象的同步方法和非同步方法这个场景是两个线程其中一个访问同步方法另一个访问非同步方法此时程序会不会串行执行呢也就是说是不是线程安全的呢我们可以确定是线程不安全的如果方法不加synchronized都是安全的那就不需要同步方法了。验证下我们的结论「两个线程分别同时访问一个或两个对象的同步方法和非同步方法是线程不安全的。」public class Condition4 implements Runnable {  static Condition4 instance  new Condition4();  Override  public void run() {  //两个线程访问同步方法和非同步方法  if (Thread.currentThread().getName().equals(Thread-0)) {  //线程0,执行同步方法method0()  method0();  }  if (Thread.currentThread().getName().equals(Thread-1)) {  //线程1,执行非同步方法method1()  www.xttblog.commethod1();  }  }  // 同步方法  private synchronized void method0() {  System.out.println(线程名  Thread.currentThread().getName()  同步方法运行开始);  try {  Thread.sleep(4000);  } catch (InterruptedException e) {  e.printStackTrace();  }  System.out.println(线程  Thread.currentThread().getName()  同步方法运行结束);  }  // 普通方法  private void method1() {  System.out.println(线程名  Thread.currentThread().getName()  普通方法运行开始);  try {  Thread.sleep(4000);  } catch (InterruptedException e) {  e.printStackTrace();  }  System.out.println(线程  Thread.currentThread().getName()  普通方法运行结束);  }  public static void main(String[] args) {  Thread thread1  new Thread(instance);  Thread thread2  new Thread(instance);  thread1.start();  thread2.start();  while (thread1.isAlive() || thread2.isAlive()) {  }  System.out.println(测试结束);  }  }  运行结果两个线程是并行执行的所以是线程不安全的。线程名Thread-0同步方法运行开始   线程名Thread-1普通方法运行开始   线程Thread-0同步方法运行结束   线程Thread-1普通方法运行结束   测试结束  结果分析问题在于此method1没有被synchronized修饰所以不会受到锁的影响。即便是在同一个对象中当然在多个实例中更不会被锁影响了。结论「非同步方法不受其它由synchronized修饰的同步方法影响」你可能想到一个类似场景多个线程访问同一个对象中的同步方法同步方法又调用一个非同步方法这个场景会是线程安全的吗场景五两个线程访问同一个对象中的同步方法同步方法又调用一个非同步方法我们来实验下这个场景用两个线程调用同步方法在同步方法中调用普通方法再用一个线程直接调用普通方法看看是否是线程安全的public class Condition8 implements Runnable {  static Condition8 instance  new Condition8();  Override  public void run() {  if (Thread.currentThread().getName().equals(Thread-0)) {  //直接调用普通方法  method2();  } else {  // 先调用同步方法在同步方法内调用普通方法  method1();  }  }  // 同步方法  private static synchronized void method1() {  System.out.println(线程名  Thread.currentThread().getName()  同步方法运行开始);  try {  Thread.sleep(2000);  } catch (InterruptedException e) {  e.printStackTrace();  }  System.out.println(线程  Thread.currentThread().getName()  同步方法运行结束,开始调用普通方法);  method2();  }  // 普通方法  private static void method2() {  System.out.println(线程名  Thread.currentThread().getName()  普通方法运行开始);  try {  Thread.sleep(4000);  } catch (InterruptedException e) {  e.printStackTrace();  }  System.out.println(线程  Thread.currentThread().getName()  普通方法运行结束);  }  public static void main(String[] args) {  // 此线程直接调用普通方法  Thread thread0  new Thread(instance);  // 这两个线程直接调用同步方法  Thread thread1  new Thread(instance);  Thread thread2  new Thread(instance);  thread0.start();  thread1.start();  thread2.start();  while (thread0.isAlive() || thread1.isAlive() || thread2.isAlive()) {  }  System.out.println(测试结束);  }  }  运行结果线程名Thread-0普通方法运行开始   线程名Thread-1同步方法运行开始   线程Thread-1同步方法运行结束,开始调用普通方法   线程名Thread-1普通方法运行开始   线程Thread-0普通方法运行结束   线程Thread-1普通方法运行结束   线程名Thread-2同步方法运行开始   线程Thread-2同步方法运行结束,开始调用普通方法   线程名Thread-2普通方法运行开始   线程Thread-2普通方法运行结束   测试结束  结果分析我们可以看出普通方法被两个线程并行执行不是线程安全的。这是为什么呢因为如果非同步方法有任何其他线程直接调用而不是仅在调用同步方法时才调用非同步方法此时会出现多个线程并行执行非同步方法的情况线程就不安全了。对于同步方法中调用非同步方法时要想保证线程安全就必须保证非同步方法的入口仅出现在同步方法中。但这种控制方式不够优雅若被不明情况的人直接调用非同步方法就会导致原有的线程同步不再安全。所以不推荐大家在项目中这样使用但我们要理解这种情况并且我们要用语义明确的、让人一看就知道这是同步方法的方式来处理线程安全的问题。所以最简单的方式是在非同步方法上也加上synchronized关键字使其变成一个同步方法这样就变成了《场景五两个线程同时访问同一个对象的不同的同步方法》这种场景下大家就很清楚的看到同一个对象中的两个同步方法不管哪个线程调用都是线程安全的了。所以结论是「两个线程访问同一个对象中的同步方法同步方法又调用一个非同步方法仅在没有其他线程直接调用非同步方法的情况下是线程安全的。若有其他线程直接调用非同步方法则是线程不安全的。」场景六两个线程同时访问同一个对象的不同的同步方法这个场景也是在探讨对象锁的作用范围对象锁的作用范围是对象中的所有同步方法。所以当访问同一个对象中的多个同步方法时结论是「两个线程同时访问同一个对象的不同的同步方法时是线程安全的。」public class Condition5 implements Runnable {  static Condition5 instance  new Condition5();  Override  public void run() {  if (Thread.currentThread().getName().equals(Thread-0)) {  //线程0,执行同步方法method0()  method0();  }  if (Thread.currentThread().getName().equals(Thread-1)) {  //线程1,执行同步方法method1()  www.xttblog.commethod1();  }  }  private synchronized void method0() {  System.out.println(线程名  Thread.currentThread().getName()  同步方法0运行开始);  try {  Thread.sleep(4000);  } catch (InterruptedException e) {  e.printStackTrace();  }  System.out.println(线程  Thread.currentThread().getName()  同步方法0运行结束);  }  private synchronized void method1() {  System.out.println(线程名  Thread.currentThread().getName()  同步方法1运行开始);  try {  Thread.sleep(4000);  } catch (InterruptedException e) {  e.printStackTrace();  }  System.out.println(线程  Thread.currentThread().getName()  同步方法1运行结束);  }  //运行结果:串行  public static void main(String[] args) {  Thread thread1  new Thread(instance);  Thread thread2  new Thread(instance);  thread1.start();  thread2.start();  while (thread1.isAlive() || thread2.isAlive()) {  }  System.out.println(测试结束);  }   }  运行结果是线程安全的。线程名Thread-1同步方法1运行开始   线程Thread-1同步方法1运行结束   线程名Thread-0同步方法0运行开始   线程Thread-0同步方法0运行结束   测试结束  结果分析两个方法method0()和method1()的synchronized修饰符虽没有指定锁对象但默认锁对象为this对象为锁对象所以对于同一个实例instance两个线程拿到的锁是同一把锁此时同步方法会串行执行。这也是synchronized关键字的可重入性的一种体现。场景七两个线程分别同时访问静态synchronized和非静态synchronized方法这种场景的本质也是在探讨两个线程获取的是不是同一把锁的问题。静态synchronized方法属于类锁锁对象是*.class对象非静态synchronized方法属于对象锁中的方法锁锁对象是this对象。两个线程拿到的是不同的锁自然不会相互影响。结论「两个线程分别同时访问静态synchronized和非静态synchronized方法线程不安全。」代码实现public class Condition6 implements Runnable {  static Condition6 instance  new Condition6();  Override  public void run() {  if (Thread.currentThread().getName().equals(Thread-0)) {  //线程0,执行静态同步方法method0()  method0();  }  if (Thread.currentThread().getName().equals(Thread-1)) {  //线程1,执行非静态同步方法method1()  method1();  }  }  // 重点用static synchronized 修饰的方法属于类锁锁对象为*.class对象。  private static synchronized void method0() {  System.out.println(线程名  Thread.currentThread().getName()  静态同步方法0运行开始);  try {  Thread.sleep(4000);  } catch (InterruptedException e) {  e.printStackTrace();  }  System.out.println(线程  Thread.currentThread().getName()  静态同步方法0运行结束);  }  // 重点synchronized 修饰的方法属于方法锁锁对象为this对象。  private synchronized void method1() {  System.out.println(线程名  Thread.currentThread().getName()  非静态同步方法1运行开始);  try {  Thread.sleep(4000);  } catch (InterruptedException e) {  e.printStackTrace();  }  System.out.println(线程  Thread.currentThread().getName()  非静态同步方法1运行结束);  }  //运行结果:并行  public static void main(String[] args) {  //问题原因 线程1的锁是类锁*.class对象线程2的锁是方法锁this对象,两个线程的锁不一样自然不会互相影响所以会并行执行。  Thread thread1  new Thread(instance);  Thread thread2  new Thread(instance);  thread1.start();  thread2.start();  while (thread1.isAlive() || thread2.isAlive()) {  }  System.out.println(测试结束);  }  运行结果线程名Thread-0静态同步方法0运行开始   线程名Thread-1非静态同步方法1运行开始   线程Thread-1非静态同步方法1运行结束   线程Thread-0静态同步方法0运行结束   测试结束  场景八同步方法抛出异常后JVM会自动释放锁的情况本场景探讨的是synchronized释放锁的场景「只有当同步方法执行完或执行时抛出异常这两种情况才会释放锁。」所以在一个线程的同步方法中出现异常的时候会释放锁另一个线程得到锁继续执行。而不会出现一个线程抛出异常后另一个线程一直等待获取锁的情况。这是因为JVM在同步方法抛出异常的时候会自动释放锁对象。代码实现public class Condition7 implements Runnable {  private static Condition7 instance  new Condition7();  Override  public void run() {  if (Thread.currentThread().getName().equals(Thread-0)) {  //线程0,执行抛异常方法method0()  method0();  }  if (Thread.currentThread().getName().equals(Thread-1)) {  //线程1,执行正常方法method1()  method1();  }  }  private synchronized void method0() {  System.out.println(线程名  Thread.currentThread().getName()  运行开始);  try {  Thread.sleep(4000);  } catch (InterruptedException e) {  e.printStackTrace();  }  //同步方法中当抛出异常时JVM会自动释放锁不需要手动释放其他线程即可获取到该锁  System.out.println(线程名  Thread.currentThread().getName()  抛出异常释放锁);  throw new RuntimeException();  }  private synchronized void method1() {  System.out.println(线程名  Thread.currentThread().getName()  运行开始);  try {  Thread.sleep(4000);  } catch (InterruptedException e) {  e.printStackTrace();  }  System.out.println(线程  Thread.currentThread().getName()  运行结束);  }  public static void main(String[] args) {  Thread thread1  new Thread(instance);  Thread thread2  new Thread(instance);  thread1.start();  thread2.start();  while (thread1.isAlive() || thread2.isAlive()) {  }  System.out.println(测试结束);  }  }  运行结果线程名Thread-0运行开始   线程名Thread-0抛出异常释放锁   线程名Thread-1运行开始   Exception in thread Thread-0 java.lang.RuntimeException  at com.study.synchronize.conditions.Condition7.method0(Condition7.java:34)  at com.study.synchronize.conditions.Condition7.run(Condition7.java:17)  at java.lang.Thread.run(Thread.java:748)   线程Thread-1运行结束   测试结束  结果分析可以看出线程还是串行执行的说明是线程安全的。而且出现异常后不会造成死锁现象JVM会自动释放出现异常线程的锁对象其他线程获取锁继续执行。总结本文总结了并用代码实现和验证了synchronized各种使用场景以及各种场景发生的原因和结论。我们分析的理论基础都是synchronized关键字的锁对象究竟是谁多个线程之间竞争的是否是同一把锁根据这个条件来判断线程是否是安全的。所以有了这些场景的分析锻炼后我们在以后使用多线程编程时也可以通过分析锁对象的方式判断出线程是否是安全的从而避免此类问题的出现。本文涵盖了synchronized关键字的最重要的各种使用场景也是面试官常常会问到的高频问题是一篇值得大家仔细阅读和亲自动手实践的文章喜欢本文请点赞和收藏。 往期推荐 线程池的7种创建方式强烈推荐你用它...求求你别再用wait和notify了2020年终总结新的“开始”关注我每天陪你进步一点点
http://www.yutouwan.com/news/239355/

相关文章:

  • 网站建设中期检查表怎么写廊坊宣传片制作公司
  • 惠安规划局建设局网站自己做的网站可以挂在哪里
  • 北京pk10网站开发公司宣传册设计与制作模板
  • win10做网站服务器咋建网站
  • 网站做邮箱星子网站建设
  • 宁晋县建设局网站php网站开发基础教程
  • 网站域名每年费用百度制作的wordpress工具
  • 从化建网站知己知彼网站
  • 安康企业网站建设价格中国工信部官网查询网站备案
  • wordpress主循环南京做网站优化公司
  • 华为云速建站教程吴中seo网站优化软件
  • 网站怎么做才能上百度首页网站建设费可以计业务费吗
  • 比如做百度知道 .html,这些都是我们不可控制的网站!网站改版要改哪些页面
  • 营销型网站建设ppt模板下载互联网保险的优势
  • 郑州网站建设网站企业网阳江一中成绩查询
  • 网站权重提升工具网站开发常见模块
  • 济南公司快速建站seo公司服务
  • 企业做网站有什么用如何将优酷视频上传到自己网站
  • 育婴网站模板公司建官网要多少钱
  • 网站后台 刷新网站开发报价单
  • 域名到期了网站会打不开吗北京哪个网站最好
  • 网站设计开发团队网站建设的条件分析
  • 流行的企业网站推广标题设计网站
  • 临沂哪里做网站施工企业降本增效的方法和措施
  • 基于asp.net网站开发湖北建设招标网 官方网站
  • wap建站模板聊城网站建设设计
  • 电子商务网站开发代码莱芜网络推广专家
  • 网站开发明细运维35岁以后会失业吗
  • 郑州网站开发招聘做动车哪个网站查
  • 一锅汤资源网站建设大全怀来县住房和城乡规划建设局网站