1. synchronized关键字

synchronized关键字保证在同一时刻,只有一个线程可以执行某个对象内某一个方法或某一段代码块。

重量级锁。包含两个特征:互斥性和可见性。

synchronized可以解决一个线程看到对象处于不一致的状态,可以保证进入同步方法或者同步代码块的每个线程都可以看到由同一个锁保护之前所有的修改效果。

实现同步的基础:Java中每个对象都可作为锁。

方法

static方法

锁的是当前类的class对象,该类的所有对象访问这个static方法都被阻塞。

非static方法

锁的是当前实例对象,必须持有该对象锁才能访问对象内的同步方法。

代码块

this对象

与锁非static方法一样,都是给对象上锁。

非this对象x

给对象x上锁,想访问这个代码段必须持有这个对象x的锁才可以。

class对象

与给static方法加同步关键字一样,锁的都是class对象。

注意:class锁和对象锁不是同一种锁。

  • 持有class锁则可以访问同步的static方法和锁定class对象的代码段;
  • 持有对象锁则可以访问同步的非static方法和锁定this对象的代码段。
  • 只有多个线程持有同一个对象的锁时,访问该对象内的同步方法才会被阻塞,如果持有的不是同一个对象的锁则异步执行。

2. wait()和notify()

wait():使一个线程处于等待状态,并且释放所持有的对象的lock。

sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedException异常。

notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。

notityAll():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。

3. 使用重入锁

在JavaSE5.0中新增了一个java.util.concurrent包来支持同步。

ReentrantLock类是可重入、互斥、实现了Lock接口的锁,它与使用synchronized方法和快具有相同的基本行为和语义,并且扩展了其能力。
ReenreantLock类的常用方法有:

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

注:关于Lock对象和synchronized关键字的选择:

  • 最好两个都不用,使用一种java.util.concurrent包提供的机制,能够帮助用户处理所有与锁相关的代码。
  • 如果synchronized关键字能满足用户的需求,就用synchronized,因为它能简化代码
  • 如果需要更高级的功能,就用ReentrantLock类,此时要注意及时释放锁,否则会出现死锁,通常在finally代码释放锁

4. await() signal() signalAll()

java.util.concurrent 类库中提供了 Condition 类来实现线程之间的协调,可以在Condition上调用 await() 方法使线程等待,其它线程调用 signal() 或 signalAll() 方法唤醒等待的线程。

相比于 wait() 这种等待方式,await() 可以指定等待的条件,因此更加灵活

使用 Lock 来获取一个 Condition 对象

5. 使用局部变量

如果使用ThreadLocal管理变量,则每一个使用该变量的线程都获得该变量的副本,副本之间相互独立,这样每一个线程都可以随意修改自己的变量副本,而不会对其他线程产生影响。

ThreadLocal 类的常用方法:

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

前面5种同步方式都是在底层实现的线程同步,但是我们在实际开发当中,应当尽量远离底层结构。 使用javaSE5.0版本中新增的java.util.concurrent包将有助于简化开发。

6. 使用阻塞队列

本小节主要是使用LinkedBlockingQueue<E>来实现线程的同步。

LinkedBlockingQueue<E>是一个基于已连接节点的,范围任意的blocking queue。

队列是先进先出的顺序(FIFO),

LinkedBlockingQueue 类常用方法:

  • LinkedBlockingQueue() : 创建一个容量为Integer.MAX_VALUE的LinkedBlockingQueue
  • put(E e) : 在队尾添加一个元素,如果队列满则阻塞
  • size() : 返回队列中的元素个数
  • take() : 移除并返回队头元素,如果队列空则阻塞

7. 使用原子变量

需要使用线程同步的根本原因在于对普通变量的操作不是原子的

原子操作就是指将读取变量值、修改变量值、保存变量值看成一个整体来操作即-这几种行为要么同时完成,要么都不完成。

在java的util.concurrent.atomic包中提供了创建了原子类型变量的工具类,使用该类可以简化线程同步。

其中AtomicInteger 表可以用原子方式更新int的值,可用在应用程序中(如以原子方式增加的计数器),但不能用于替换Integer;

可扩展Number,允许那些处理机遇数字类的工具和实用工具进行统一访问。

AtomicInteger类常用方法:

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

注:

--volatile关键字

轻量级synchronized,使用成本低,不会引起上下文切换和调度。

volatile变量在线程内存中被修改之后要立即同步回主内存中,以保证其他线程使用该volatile关键字修饰的变量时获取到的是最新的变量值。

volatile关键字保证的是变量在不同线程之间的可见性,但是无法保证原子性,对于多个线程访问同一个实例变量还是需要加锁同步。

  • 比如自增操作!!!

---

synchronized与Lock的区别

两者区别:

1.首先synchronized是java内置关键字,在jvm层面,Lock是个java类;

2.synchronized无法判断是否获取锁的状态,;

3.synchronized会自动释放锁(a 线程执行完同步代码会释放锁 ;b 线程执行过程中发生异常会释放锁),Lock需在finally中手工释放锁(unlock()方法释放锁),否则容易造成线程死锁;

4.用synchronized关键字的两个线程1和线程2,如果当前线程1获得锁,线程2线程等待。如果线程1阻塞,线程2则会一直等待下去,而Lock锁就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了;

5.synchronized的锁可重入、不可中断、非公平,而Lock锁可重入、可判断、可公平(两者皆可)

6.Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。

参考:https://blog.csdn.net/scgyus/article/details/79499650

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

  1. JAVA中线程同步的方法(7种)汇总

    JAVA中线程同步的方法(7种)汇总 同步的方法: 一.同步方法 即有synchronized关键字修饰的方法. 由于java的每个对象都有一个内置锁,当用此关键字修饰方法时, 内置锁会保护整个方法. ...

  2. JAVA中线程同步的几种实现方法

    JAVA中线程同步的几种实现方法 一.synchronized同步的方法: 1.synchronized同步方法 即有synchronized关键字修饰的方法. 由于java的每个对象都有一个内置锁, ...

  3. Java创建线程池的方式

    Java创建线程池的方式 文章目录 Java创建线程池的方式 一.通过Executors工厂方法创建 1.Executors.newSingleThreadExecutor() 2.Executors ...

  4. 关于C语言中线程同步的方式

    C语言中线程同步的方式 线程同步 互斥锁 读写锁 条件变量 信号量 线程同步 在多线程环境中,线程之间由于竞争共享资源(临界资源)容易引起数据不一致的问题.一般采用互斥锁(互斥信号量)解决,保证只有一 ...

  5. JAVA跨线程传递数据方式总结

    实现跨线程传递数据方式: v1:子线程使用主线程的局部变量 这种当主线程和子线程不在一快儿时就不适用.可以使用JDK原生的InheritableThreadLocal. v2:InheritableT ...

  6. Java高级-线程同步机制实现

    2019独角兽企业重金招聘Python工程师标准>>> 前言 我们可以在计算机上运行各种计算机软件程序.每一个运行的程序可能包括多个独立运行的线程(Thread). 线程(Threa ...

  7. 快点来学吧!java保证线程安全的方式

    JAVA基础 JAVA异常分类及处理 异常分类 异常的处理方式 Throw和throws的区别 JAVA反射 动态语言 反射机制概念 (运行状态中知道类所有的属性和方法) Java反射API 反射使用 ...

  8. Java 多线程 线程同步

    线程同步 1.发生在多个线程操作同一个资源 2.并发:同一个对象被多个线程同时操作 3.于是,就需要线程同步.线程同步其实就是一种等待机制,多个需要同时访问此对象的线程进入这个对象的等待池形成队列,等 ...

  9. java实现线程同步的方法_Java实现线程同步方法及原理详解

    一.概述 无论是什么语言,在多线程编程中,常常会遇到多个线同时操作程某个变量(读/写),如果读/写不同步,则会造成不符合预期的结果. 例如:线程A和线程B并发运行,都操作变量X,若线程A对变量X进行赋 ...

最新文章

  1. Android 的NDK的Makefile编写
  2. 如何将传统OA移动化?
  3. c语言是一门对标识符大小写敏感的程序设计语言,《C语言程序设计》课程自测题...
  4. 一篇文章带你搞定Python返回函数
  5. 计算机画面的音乐素材,音效素材:高科技用户界面UI点触计算机数据分析全息音效合集...
  6. oracle数值型转为char类型,PLSQL: Oracle函数to_char转化数字型指定小数点位数的技巧...
  7. 信息学奥赛一本通(1253:抓住那头牛)
  8. 拳王虚拟项目公社:闲鱼操作虚拟资源的案例拆解,教你玩转闲鱼虚拟资源,货源+方法
  9. 计算机与交互式白板通过USB数据线,选购交互式电子白板注意哪些事项【详细介绍】...
  10. pojo类中的布尔类型的变量为什么不能加is
  11. 如何在CSDN上发gif - 超简单版本
  12. python(分隔符)
  13. Simon Knowles:30年做成三家独角兽公司,AI芯片创业的底层逻辑
  14. 解决memoryerror
  15. spi子系统实现数码管控制
  16. 51 nod 1625 夹克爷发红包【贪心、二进制枚举】
  17. windows设备管理器_如何打开Windows设备管理器?
  18. Duang~Shark 闪跌 99%! Fork 了 Bunny 的代码还 Fork 了它的攻击
  19. 2019年度技术总结
  20. 深入理解 Android 9.0 Crash 机制(二)

热门文章

  1. Python牛刀小试(五)--logging模块
  2. ConcurrentSkipListMap深入分析
  3. 项目管理中,最难管的是什么?(转)
  4. linux下JNI的demo
  5. Java数据类型和MySql数据类型对应表
  6. WSE 3.0异步调用, MTOM, Custom Policy Trace Assertion
  7. 【Anaconda】安装源---豆瓣,清华
  8. go gin框架:请求静态图片资源(可用于搭建图床等应用)
  9. linux read while 变量运算
  10. deepin/Ubuntu安装最新版docker-ce命令整理