当前位置: 首页 > 后端技术 > Java

Java线程同步的四种方法详解(推荐收藏)

时间:2023-04-01 21:23:07 Java

Java线程同步是Java多线程和并发编程的核心点,需要掌握。下面我来详细解释一下Java线程同步的四种主要实现方式@mikechen目录什么是线程同步线程同步的几种方式1.使用synchronized关键字2.使用ReentrantLock3.使用原子变量实现线程同步4.ThreadLocal实现threadsynchronization什么是线程同步当使用多个线程访问同一个数据时,会导致数据不准确,相互之间会发生冲突,很容易出现线程安全问题,如下图:例如,多线程正在操作同一个数据,打算修改商品库存,会导致数据不一致。线程同步的真正含义其实是“排队”:几个线程需要排队,一个一个对共享资源进行操作,而不是同时进行。所以我们使用同步机制来解决这些问题,加上同步锁,避免在线程未完成操作之前被其他线程调用,从而保证了变量的唯一性和准确性。线程同步的几种方法1.使用synchronized关键字这种方法比较灵活,修改一个代码块,修改后的代码块称为同步语句块。它的作用范围是花括号{}括起来的代码,作用的对象是调用这个代码块的对象,如下:synchronized(object){//获取对象的锁来操作synchronized代码需要同步的;}![]()通常不需要同步整个方法,只需要使用synchronized代码块同步关键代码即可。具体例子如下:publicclassSynchronizedThread{classBank{privateintaccount=200;publicintgetAccount(){返回账户;}/***用同步方法实现**@parammoney*/publicsynchronizedvoidsave(intmoney){account+=money;}/***使用同步代码块实现**@parammoney*/publicvoidsave1(intmoney){synchronized(this){account+=money;}}}类NewThread实现Runnable{privateBankbank;publicNewThread(银行银行){this.bank=bank;}@Overridepublicvoidrun(){for(inti=0;i<10;i++){//bank.save1(10);银行.save(10);System.out.println(i+"账户余额为:"+bank.getAccount());}}}/***创建线程并调用内部class*/publicvoiduseThread(){银行bank=newBank();NewThreadnew_thread=newNewThread(bank);System.out.println("线程1");线程thread1=newThread(new_thread);thread1.start();System.out.println("线程2");线程thread2=newThread(new_thread);thread2.start();}publicstaticvoidmain(String[]args){SynchronizedThreadst=newSynchronizedThread();st.useThread();}}![]()2.使用ReentrantLockReentrantLock类是一个实现了Lock接口的可重入互斥锁。它具有与使用同步方法相同的基本行为和语义,并扩展了它的能力私人账户=100;//需要声明这个锁privateLocklock=newReentrantLock();publicintgetAccount(){返回账户;}//不需要synchronizedpublicvoidsave(intmoney){lock.lock();尝试{帐户+=金钱;}最后{lock.unlock();}}}![]()Synchronizedvs.LockReentrantLock是显示锁,手动开锁和关锁,别忘了关锁;synchronized是隐藏的ReentrantLock只有代码块锁,synchronized有代码块锁和方法锁;使用ReentrantLock锁,JVM会花更少的时间调度线程,线程性能更好,具有更好的可扩展性(提供更多的子类);使用优先顺序:ReentrantLock>synchronized同步代码块>synchronized同步方法3.使用原子变量实现线程同步为了完成线程同步,我们将使用原子变量(Atomic*开头)来实现。比如一个典型的代表:java.util.concurrent.atomic中存在AtomicInteger类,它代表一个支持原子操作的整数,使用getAndIncrement方法以原子方式递增当前值。具体例子如下:privateAtomicIntegeraccount=newAtomicInteger(100);publicAtomicIntegergetAccount(){返回账户;}publicvoidsave(intmoney){account.addAndGet(money);}![]()4.ThreadLocal实现线程同步如果使用ThreadLocal来管理变量,每个使用该变量的线程都会得到一份该变量的副本,副本之间相互独立,这样每个线程都可以修改自己的随意复制变量而不影响其他线程。从而实现线程同步。具体代码示例如下://只改变Bank类,其余代码同上publicclassBank{//创建一个线程局部变量ThreadLocalprivatestaticThreadLocalaccount=newThreadLocal(){@Override//返回当前线程protected的“初始值”IntegerinitialValue(){return100;}};publicvoidsave(intmoney){//在线程复制中设置值account.set(account.get()+money);}publicintgetAccount(){//返回线程中的值copyreturnaccount.get();}}![]()以上作者简介陈锐|mikechen,10年+大厂架构经验,《BAT架构技术500期》系列文章作者,专注于互联网架构技术。阅读更多关于mikechen的InternetArchitectureJavaConcurrency的技术文章|虚拟机|数据库|春天|雷迪斯|分布式|高并发