这里抛砖引玉,为何要使用同步?

当多个线程同时操作一个可共享的资源时会出现线程安全问题,将会导致数据不一致,因此使用同步锁来防止该操作执行完之前不许被其他线程执行,从而保证了该变量的唯一性和准确性。下面总结一些java线程实现同步方式,大致有下面几种:

1.同步方法 
    使用 synchronized关键字,可以修饰普通方法、静态方法,以及语句块。由于java的每个对象都有一个内置锁,当用此关键字修饰方法时, 内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。需要注意的是调用静态方法时,锁住的不是对象,锁住的是类。

 //修饰普通方法public synchronized void add(){}//修饰语句块synchronized(object){ }//修饰静态方法public static synchronized int increase(){}

同步是一种高开销的操作,因此应该尽量减少同步的内容。 通常没有必要同步整个方法,使用synchronized代码块同步关键代码即可。 
      
2.使用特殊域变量(volatile)实现线程同步

  • volatile关键字为域变量的访问提供了一种免锁机制,
  • 使用volatile修饰域相当于告诉虚拟机该域可能会被其他线程更新,
  • 因此每次使用该域就要重新计算,而不是使用寄存器中的值
  • volatile不会提供任何原子操作,它也不能用来修饰final类型的变量

多线程中的非同步问题主要出现在对域的读写上,如果让域自身避免这个问题,则就不需要修改操作该域的方法。 
    用final域,有锁保护的域和volatile域可以避免非同步的问题。 
    
3.使用重入锁实现线程同步

在JavaSE5.0中新增了一个java.util.concurrent包来支持同步。 ReentrantLock类是可重入、互斥、实现了Lock接口的锁, 
    它与使用synchronized方法和快具有相同的基本行为和语义,并且扩展了其能力。
    ReenreantLock类的常用方法有:

  • ReentrantLock() : 创建一个ReentrantLock实例
  • lock() : 获得锁
  • unlock() : 释放锁

ReentrantLock()还有一个可以创建公平锁的构造方法,但由于能大幅度降低程序运行效率,不推荐使用 
   关于Lock对象和synchronized关键字的选择: 
        a.最好两个都不用,使用一种java.util.concurrent包提供的机制, 
            能够帮助用户处理所有与锁相关的代码。 
        b.如果synchronized关键字能满足用户的需求,就用synchronized,因为它能简化代码 
        c.如果需要更高级的功能,就用ReentrantLock类,此时要注意及时释放锁,否则会出现死锁,通常在finally代码释放锁 
        
4.使用局部变量实现线程同步 
       如果使用ThreadLocal管理变量,则每一个使用该变量的线程都获得该变量的副本, 副本之间相互独立,这样每一个线程都可以随意修改自己的变量副本,而不会对其他线程产生影响。

ThreadLocal 类的常用方法

  • ThreadLocal() : 创建一个线程本地变量
  • get() : 返回此线程局部变量的当前线程副本中的值
  • initialValue() : 返回此线程局部变量的当前线程的"初始值"
  • set(T value) : 将此线程局部变量的当前线程副本中的值设置为value

ThreadLocal与同步机制 
        a.ThreadLocal与同步机制都是为了解决多线程中相同变量的访问冲突问题。 
        b.前者采用以"空间换时间"的方法,后者采用以"时间换空间"的方式

5.使用阻塞队列实现线程同步

上面的实现方式都是在底层实现的线程同步,但是我们在实际开发当中,应当尽量远离底层结构。 使用javaSE5.0版本中新增的java.util.concurrent包将有助于简化开发。 例如使用LinkedBlockingQueue<E>来实现线程的同步 。
    LinkedBlockingQueue<E>是一个基于已连接节点的,范围任意的blocking queue。 
    队列是先进先出的顺序(FIFO),关于队列以后会详细讲解~ 
    LinkedBlockingQueue 类常用方法 
    LinkedBlockingQueue() : 创建一个容量为Integer.MAX_VALUE的LinkedBlockingQueue 
    put(E e) : 在队尾添加一个元素,如果队列满则阻塞 
    size() : 返回队列中的元素个数 
    take() : 移除并返回队头元素,如果队列空则阻塞

BlockingQueue<E>定义了阻塞队列的常用方法,尤其是三种添加元素的方法,我们要多加注意,当队列满时:

  • add()方法会抛出异常
  • offer()方法返回false
  • put()方法会阻塞

6.使用原子变量实现线程同步
     原子操作就是指将读取变量值、修改变量值、保存变量值看成一个整体来操作,即-这几种行为要么同时完成,要么都不完成。在java的util.concurrent.atomic包中提供了创建了原子类型变量的工具类,使用该类可以简化线程同步。其中AtomicInteger 表可以用原子方式更新int的值,可用在应用程序中(如以原子方式增加的计数器),但不能用于替换Integer;可扩展Number,允许那些处理机遇数字类的工具和实用工具进行统一访问。
AtomicInteger类常用方法:

  • AtomicInteger(int initialValue) : 创建具有给定初始值的新的AtomicInteger
  • addAddGet(int dalta) : 以原子方式将给定值与当前值相加
  • get() : 获取当前值

代码实例:

 1 class Bank {2         private AtomicInteger account = new AtomicInteger(100);3 4         public AtomicInteger getAccount() {5             return account;6         }7 8         public void save(int money) {9             account.addAndGet(money);
10         }
11 } 

补充--原子操作主要有:
  对于引用变量和大多数原始变量(long和double除外)的读写操作;
  对于所有使用volatile修饰的变量(包括long和double)的读写操作。

java线程同步的实现方式相关推荐

  1. Java线程同步的几种方式

    Java线程同步的几种方式 1.使用synchronized关键字  它的工作是对同步的代码加锁,使得每一次只能有一个线程进入同步块,从而保证线程间的安全性.  synchronized关键字的用法: ...

  2. java线程 同步与异步 线程池

    1)多线程并发时,多个线程同时请求同一个资源,必然导致此资源的数据不安全,A线程修改了B线 程的处理的数据,而B线程又修改了A线程处理的数理.显然这是由于全局资源造成的,有时为了解 决此问题,优先考虑 ...

  3. Java线程同步-模拟买票

    文章首发于 2020-11-29 知乎文章:Java线程同步-模拟买票 作者:落雨湿红尘(也是我o) 01 导语 本文使用JAVA代码模拟买票场景下的业务交互,通过示例讲解线程的初始化.线程同步等ja ...

  4. Java --- 线程同步和异步的区别

    1. Java 线程 同步与异步 多线程并发时,多个线程同时请求同一个资源,必然导致此资源的数据不安全,A线程修改了B线程的处理的数据,而B线程又修改了A线程处理的数理.显然这是由于全局资源造成的,有 ...

  5. Java线程--同步和异步的区别

    本文转自https://blog.csdn.net/u011033906/article/details/53840525 1. Java 线程 同步与异步 多线程并发时,多个线程同时请求同一个资源, ...

  6. Java线程同步内存实现

    Java线程同步内存实现 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 例如:第一章 Python 机器学习入门之pandas的使用 提示:写完文章后,目录可以自动生成,如何生成可 ...

  7. java线程间通信的方式

    java线程间通信的方式 1. 共享变量 2. 等待/通知 3. 管道流 1. 共享变量 volatile修饰的变量,线程间可见,可使用这种变量作为线程间传递消息的媒介: 延伸出来的,还有redis中 ...

  8. (转) Java线程同步阻塞, sleep(), suspend(), resume(), yield(), wait(), notify()

    为了解决对共享存储区的访问冲突,Java 引入了同步机制.但显然不够,因为在任意时刻所要求的资源不一定已经准备好了被访问,反过来,同一时刻准备好了的资源也可能不止一个. 为解决访问控制问题,Java ...

  9. 关于java线程同步的笔记_线程同步(JAVA笔记-线程基础篇)

    在多线程应用程序中经常会遇到线程同步的问题.比如:两个线程A.线程B可能会 "同时" 执行同一段代码,或修改同一个变量.而很多时候我们是不希望这样的. 这时候,就需要用到线程同步. ...

最新文章

  1. 【网络流24题】解题报告:E 、圆桌问题(最大流求二分图多重匹配)
  2. jenkins环境搭建
  3. django多线程_Django两种启动方式(runserver和uwsgi)的区别
  4. 类操作是什么意思?jQuery的类操作教程分享
  5. java泛型(三)、通配符的使用
  6. InterruptedException和中断线程的解释
  7. W10关闭不必要的服务
  8. 腾讯牵手数十家合作伙伴发起“光合计划” 推动“百千万”三大目标落地
  9. 三度其二——矢量场的散度
  10. android 异步加载图片缩略图
  11. python isfile_基于Python中isfile函数和isdir函数使用详解
  12. C#:判断数组中有没有某个值的方法
  13. 投资62笔!私募巨头凯雷的“中国生意经”
  14. AM5728 + 映美精工业相机图像处理案例
  15. Java 第三方ui库_Uiautomator打包使用第三方库,报错的解决方案
  16. outlook企业邮箱服务器要多少钱,如何用OUTLOOK使用企业邮箱
  17. 经典重写alert方法
  18. PMP学习笔记 第3章 项目经理的角色
  19. win 2016 ssh_【Win】Print Conductor 全能批量打印工具兼容所有打印机
  20. 高手谈谈PR更新前站长们应该如何去做

热门文章

  1. 淘淘商城第103讲——js跨域分析
  2. PHP实现qq邮箱发送自定义邮件
  3. php小米订单组,解析电商订单号的生成
  4. 刺客信条:起源-概念艺术
  5. html margin word无效,margin下边距怎么设置
  6. 淘宝API 淘宝商品评论列表
  7. 自学算法,我是如何从小白到拿到大厂offer的
  8. 名画154 顾安《画选四幅》
  9. RNA-seq(2):下载参考基因组及基因注释,及测序数据-学习笔记
  10. 生活大爆炸(TBBT): 台词爬取、词云生成与NLP分析