首页 > 其他分享 >关于synchronized

关于synchronized

时间:2023-09-04 18:24:10浏览次数:24  
标签:Thread synchronized 对象 类锁 实例 线程 关于 new

  1. 关于synchronized

    synchronized是java中的关键字,可以在需要线程安全的业务场景中进行使用,保证线程安全,它是利用锁机制来实现同步的。

  2. synchronized锁对象和锁类

    1. 对象锁:每个实例都会有一个monitor对象,即Java对象的锁,类的对象可以有多个,所以每个对象有其独立的对象锁,互不干扰
    2. 类锁:每个类只有一个Class对象,所以每个类只有一个类锁;类锁是加载类上的,而类信息是存在JVM方法区的,并且整个JVM只有一份,方法区又是所有线程共享的,所以类锁是所有线程共享的
    3. 原理参考:底层原理 https://javaguide.cn/java/concurrent/java-concurrent-questions-02.html#synchronized-%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86%E4%BA%86%E8%A7%A3%E5%90%97
  3. 实战使用

    1. 多个线程操作相同对象

      /**
       * @Author wsz
       * @Description 多个线程操作同一个资源, 同时只有一个线程执行成功,使用对象锁或类锁都可以
       */
      public class SellTicket implements Runnable {
          private int ticketNum = 100;
          public boolean loop = true;
      
          //每个对象都有自己的锁
          Object obj = new Object();
      
          public void sell() {
              synchronized (obj) {
                  if (ticketNum <= 0) {
                      loop = false;
                      return;
                  }
                  System.out.println(Thread.currentThread().getName() + " 卖了第" + ticketNum + "张票,还剩" + --ticketNum);
              }
      
          }
      
          @Override
          public void run() {
              while (loop) {
                  sell();
              }
          }
      }
      
      class Test {
          public static void main(String[] args) {
              SellTicket sellTicket = new SellTicket();
              // 多个线程操作同一个对象 使用同一个对象锁obj,同一时刻只能有一个线程执行sell方法内的代码块
              Thread thread1 = new Thread(sellTicket);
              Thread thread2 = new Thread(sellTicket);
              Thread thread3 = new Thread(sellTicket);
              thread1.start();
              thread2.start();
              thread3.start();
          }
      }
      
    2. 每个线程操作不同对象

      package com.pj.project.sys_user_sync.secure;
      
      /**
       * @Author wsz
       * @Description 这个示例中,我们创建了两个不同的BankAccount对象实例 account1 和 account2。每个对象实例都有自己的锁。
       * 当线程thread1和thread2分别对account1和account2调用withdraw()方法时,它们会尝试获取各自对象实例的锁
       * 这意味着每次只有一个线程可以执行withdraw()方法,并且其他线程必须等待锁的释放。通过使用对象级别的锁,
       * 我们可以确保同一时间只有一个线程能够从特定的账户中进行取款操作,避免了数据不一致和竞态条件的问题。
       */
      public class BankAccount {
          private int balance;
      
          public BankAccount(int balance) {
              this.balance = balance;
          }
      
          public void withdraw(int amount) {
              // 不同线程获取各自对象实例的锁
              synchronized (this) {
                  if (balance >= amount) {
                      balance -= amount;
                      System.out.println(Thread.currentThread().getName() + " 完成取款:" + amount+"还剩"+balance);
                  } else {
                      System.out.println(Thread.currentThread().getName() + " 取款失败,余额不足");
                  }
              }
          }
      }
      
      class Main1 {
          public static void main(String[] args) {
              //每个线程操作不同对象 使用同一个对象锁obj,同一时刻只能有一个线程执行sell方法内的代码块
              //账户1
              BankAccount account1 = new BankAccount(1000);
              //账户2
              BankAccount account2 = new BankAccount(2000);
      
              Thread thread1 = new Thread(() -> {
                  for (int i = 0; i < 5; i++) {
                      //从账户1取款
                      account1.withdraw(200);
                      try {
                          Thread.sleep(500);
                      } catch (InterruptedException e) {
                          throw new RuntimeException(e);
                      }
                  }
              });
      
              Thread thread2 = new Thread(() -> {
                  for (int i = 0; i < 10; i++) {
                      //从账户2取款
                      account2.withdraw(300);
                      try {
                          Thread.sleep(500);
                      } catch (InterruptedException e) {
                          throw new RuntimeException(e);
                      }
                  }
              });
      
              Thread thread3 = new Thread(() -> {
                  for (int i = 0; i < 5; i++) {
                      //从账户1取款
                      account1.withdraw(200);
                      try {
                          Thread.sleep(500);
                      } catch (InterruptedException e) {
                          throw new RuntimeException(e);
                      }
                  }
              });
      
              thread1.start();
              thread2.start();
              thread3.start();
          }
      }
      
  4. 对象锁和类锁使用场景

    1. 对象锁适用于处理对象实例的并发访问,保护对象状态的一致性。每个对象实例都拥有自己的锁,因此可以独立地控制并发访问。不同对象实例之间的锁是相互独立的,互不影响。
    2. 类锁适用于处理类的静态变量或静态方法的并发访问,保护全局状态的一致性。所有类的实例对象共享同一个类锁,只能有一个线程同时获取锁,确保全局资源的同步访问。
    3. 因此,如果存在多个对象实例,每个实例之间需要独立控制并发访问,应该选择对象锁。而如果需要保护全局状态或静态资源,并且所有实例对象共享同一个锁,应该选择类锁。

标签:Thread,synchronized,对象,类锁,实例,线程,关于,new
From: https://www.cnblogs.com/upupup-999/p/17677772.html

相关文章

  • 关于使用new Integer还是Integer.valueOf的研究
    作者:fbysss前言:最近看到这样的说法:使用Integer.valueOf代替newInteger更有效率,原因是研究了Integer源码,发现有一个缓存可以利用。对此我也一探究竟。发现这其实与Java的自动装箱拆箱有关,直接使用Integeri=数值的方式即可。通过字节码研究是比较有效的方式。那我们来看看吧:-----......
  • 关于NFC、谷歌钱包的理解
    NFC:NearFieldCommunication即近距离通讯技术RFID(RadioFrequencyIDentification)技术,又称电子标签、无线射频识别,公交卡就是使用这种技术。NFC传输范围较小,安全、低功耗RFID是一种识别技术,而NFC是一种交互的通信方式。有人说,NFC是RFID的一种改良版本。目前智能手机将支持NFC,也......
  • 关于JVM的server/client版本
     区别:Client启动快些,Server版进行了优化,运行会快一些,但启动会慢些。查看当前JVM版本:java-version位置:jre/bin/server  jre/bin/client两个jvm文件大小都不一样。如果没有指定JVM版本,会自动根据OS和硬件环境进行识别。windows下默认是client,Unix下,会进行Server-ClassMachine......
  • synchronized关键字
    synchronized方法声明时使用,放在范围操作符(public等)之后,返回类型声明(void等)之前。一次只能有一个线程进入该方法,其他线程想要调用该方法,只能排队等候,当前线程(就是在synchronized方法内部的线程)执行完该方法后,别的线程才能进入。publicsynchronizedvoidfunc(){//TOD......
  • 关于VIM以插入模式粘贴
    Pasteininsertmode?是否可以在Vim中以插入模式粘贴?在插入模式下,按CTRL-R{register}例子:CTRL-R*将插入剪贴板的内容CTRL-R"(未命名的寄存器)插入最后的删除或取消。要在vim的帮助中找到此内容,请键入:hi_ctrl-r相关讨论是的,我直到最近才了解CTRL-R及其非常有......
  • 关于nvim-tree的简单设置
    前言最近临近开学,为了方便在课堂上随手写一点作业,我开始对neovim进行配置,尽量让它满足一个类Ide的功能,那么必不可少的就是文件树的功能,那么这里,我就来简单记录一下nvim-tree的配置过程。这里我们使用packer插件管理器,对插件进行安装。需求neovim>=0.8.0nvim-web-deviconsis......
  • 关于建立时间,保持时间以及对应的slack的计算
    什么是建立时间,保持时间1.建立时间是指,对于DFlipflop来说,在时钟上升沿到来之前,数据输入端保持不变的最小时间2.保持时间是指,对于DFlipflop来说,在时钟上升沿到来之后,数据输入端保持不变的最小时间*一旦数据输入端违反了建立时间和保持时间的要求,那么DFlipflop就可能会......
  • 关于裸机开发和Linux开发Q&A
    一、嵌入式应用开发,选哪些单片机选择哪些单片机,需要根据具体的应用需求、性能要求和开发难度等综合因素来进行评估。以下是一些常用的嵌入式操作系统所支持的单片机类型,供参考:ARMCortex-M系列:这是一个广泛使用的嵌入式处理器体系结构,支持多种硬件平台和软件框架。Corte......
  • 关于 Product Pipeline 的 galectin.json 文件
    ProductPipeline概述:"ProductPipeline"是一个广泛用于企业中的术语,指的是一个产品从概念到最终交付的整个过程。它代表了产品的生命周期,从概念、规划、设计、开发、测试、部署,一直到最终发布和维护。在软件开发领域,"ProductPipeline"通常包括多个阶段和环节,每个环节都有特定的......
  • 使用synchronized关键字来同步多个线程操作同一个文件
    使用synchronized关键字来同步多个线程操作同一个文件importjava.io.FileWriter;importjava.io.IOException;publicclassFileSyncExample{privatestaticObjectfile=newObject();publicstaticvoidmain(String[]args)throwsInterruptedException{......