同步

同步,字面来看,有点一起工作的意思。但在线程同步中,“同”意为协同、互相配合。

比如:

A、B两个线程,并不是说两个线程必须同时一起工作,而是说互相配合工作,在某个时间可能线程A要等线程B去工作,之后线程A才能继续工作。如果理解不了,可以参考java线程(2)——模拟生产者与消费者中的例子。

思考:

为什么会有线程同步?上面例子中线程A为什么要等B工作之后才能继续工作?

在生产者和消费者的例子中,作为消费者,如果生产者还没生产,他就没办法消费只能等着,否则就会出现问题。同样,生产者也不能无止尽的生产,毕竟篮子的容量是有限的。

如果这个例子看不出来问题的严重性,我们可以想想银行取钱的例子,出现问题这后果就相当严重了。所以,多线程如果使用不当,很容易出现线程不安全的问题。尤其涉及同步问题时,一定要小心使用。

实现方式

主要有两种:synchronized和lock,前者被称为内置锁,后者叫外置锁。

关于这两者的不同之处,介绍之后再比较。

1、 synchronized关键字

在消费者和生产者的例子中,我们使用到了synchronized关键字,将篮子的“取”和“放”都做了限制,来实现线程同步。

2、lock

先来看一下他的接口定义,也是在包java.util.concurrent下。

  1. package java.util.concurrent.locks;
  2. public interface Lock {
  3. void lock();
  4. void lockInterruptibly() throws InterruptedException;
  5. boolean tryLock();
  6. void unlock();
  7. Condition newCondition();
  8. }

在上篇博客中介绍了一个使用synchronized关键字实现打印当前时间的方法,我们这里来修改一下。

  1. /**
  2. * 获得当前时间
  3. */
  4. public static void getTime() {
  5. lock.lock();
  6. try {
  7. System.out.println("1、进入获取时间方法=====");
  8. Date date = new Date();
  9. DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  10. String time = format.format(date);
  11. System.out.println("2、" + Thread.currentThread().getName() + ":"
  12. + time);
  13. System.out.println("3、获取时间成功=====");
  14. System.out.println();
  15. } finally {
  16. lock.unlock();
  17. }
  18. }
  19. //调用
  20. static Lock lock=null;
  21. public static void main(String[] args) {
  22. lock = new ReentrantLock();
  23. for (int i = 0; i < 100; i++) {
  24. new Thread(new Runnable() {
  25. @Override
  26. public void run() {
  27. getTime();
  28. }
  29. }).start();
  30. }
  31. }

结果同样满足条件:

读写锁

Lock中的另一个亮点就是对读写锁的支持。在读写锁中,把对共享资源的访问者划分为读者和写者,读者进行读访问,写者进行写操作。但是,一个读写锁同时能有一个或多个读者,但不能同时既有读者又有写者。

java中的类为ReadWriteLock,提供了读锁和写锁的方法,返回类型都是Lock

  1. public interface ReadWriteLock {
  2. Lock readLock();
  3. Lock writeLock();
  4. }

举个例子:

在例子中,data为所要读写的数据,提供了读和写的方法。

  1. private Object data = null;// 共享数据
  2. /**
  3. * 读数据
  4. */
  5. public void get() {
  6. try {
  7. //准备数据
  8. System.out.println(Thread.currentThread().getName()
  9. + " be ready to read data!");
  10. //sleep一段时间,主要为了更明显的体现出差别,无实际意义
  11. Thread.sleep((long) (Math.random() * 1000));
  12. //打印取出数据
  13. System.out.println(Thread.currentThread().getName()
  14. + "have read data :" + data);
  15. } catch (InterruptedException e) {
  16. e.printStackTrace();
  17. }
  18. }
  19. /**
  20. * 写数据
  21. *
  22. * @param data
  23. */
  24. public void put(Object data) {
  25. try {
  26. System.out.println(Thread.currentThread().getName()
  27. + " be ready to write data!");
  28. Thread.sleep((long) (Math.random() * 1000));
  29. this.data = data; // 给data赋值
  30. System.out.println(Thread.currentThread().getName()
  31. + " have write data: " + data);
  32. } catch (InterruptedException e) {
  33. e.printStackTrace();
  34. }
  35. }

执行结果:

从结果上看,当程序刚启动时,多个读写线程同时触发,等待执行。无法实现“多读”,也影响了写的操作。

那么,现在来看下加上读写锁之后的效果。

  1. ReadWriteLock rwl = new ReentrantReadWriteLock();
  2. /**
  3. * 读数据
  4. */
  5. public void get(){
  6. rwl.readLock().lock(); //读锁
  7. try {
  8. ....略
  9. } catch (InterruptedException e) {
  10. e.printStackTrace();
  11. }finally{
  12. rwl.readLock().unlock(); //释放读锁
  13. }
  14. }

与上面没有使用读写锁相比,最大的不同在于,他可以实现“多读”,并且“读”与“写”互斥。例如:Thread0,2,4进入之后,可以同时读数据。并没有多条写数据同时写。

点睛之笔

1)Lock与ReadWriteLock

以Lock第一个例子ReentrantLock来说,他实现了标准的互斥操作,有点“独占”的感觉。这种情况下,不允许多读,多写,读写等情况发生。

读写锁ReadWriteLock中,允许多个读线程同时访问一个资源,但不允许多个写线程同时访问。更符合实际操作和需要。

2)Lock与synchronized

synchronized比较武断,只能实现互斥,无法实现读写锁的允许多读操作。在并发量比较小的情况下,他是一个不错的选择。但并发量较大的话,他的性能下降很严重。

Lock锁技术除了第一点介绍的优点外,他还具有可重入性,即可以进行多次加锁,也更具公平性。不过为了避免死锁,需要在finally中释放锁。

java线程(4)——线程同步的锁技术的更多相关文章

  1. Java 虚拟机:互斥同步、锁优化及synchronized和volatile

    互斥同步 互斥同步(Mutual Exclusion & Synchronization)是常见的一种并发正确性保证手段.同步是指子啊多个线程并发访问共享数据时,保证共享数据在同一时刻只能被一 ...

  2. Java多线程02(线程安全、线程同步、等待唤醒机制)

    Java多线程2(线程安全.线程同步.等待唤醒机制.单例设计模式) 1.线程安全 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果是一样的,而且其他的变量 ...

  3. java 线程Thread 技术--线程状态与同步问题

    线程技术第三篇: 线程的状态: 1. 创建状态: 当用new 操作符创建一个新的线程对象时,该线程就处于创建状态,系统不为它分配资源 2.可运行状态:当线程调用start 方法将为线程分配必须的系统资 ...

  4. Java基础学习笔记: 多线程,线程池,同步锁(Lock,synchronized )(Thread类,ExecutorService ,Future类)(卖火车票案例)

    多线程介绍 学习多线程之前,我们先要了解几个关于多线程有关的概念.进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 线 ...

  5. JAVA语言规范-线程和锁章节之同步、等待和通知

    JAVA语言规范:线程和锁 1 同步 java编程语言提供了线程间通信的多种机制.这些方法中最基本的是同步化,此方法是使用监视器实现的.JAVA中每个对象与一个监视器相关联,一个线程可以加锁和解锁监视 ...

  6. Java线程:线程的同步与锁

    一.同步问题提出 线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏. 例如:两个线程ThreadA.ThreadB都操作同一个对象Foo对象,并修改Foo对象上的数据. public ...

  7. java线程(2)--同步和锁

    参考转载:http://rainyear.iteye.com/blog/1734311 http://turandot.iteye.com/blog/1704027 http://www.cnblog ...

  8. Java多线程-线程的同步与锁

    一.同步问题提出 线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏.例如:两个线程ThreadA.ThreadB都操作同一个对象Foo对象,并修改Foo对象上的数据. package ...

  9. (转)Java线程:线程的同步与锁

      Java线程:线程的同步与锁       一.同步问题提出   线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏. 例如:两个线程ThreadA.ThreadB都操作同一个对象Fo ...

随机推荐

  1. leetcode笔记(三)207. Course Schedule

    题目描述(原题目链接) There are a total of n courses you have to take, labeled from 0 to n-1. Some courses may ...

  2. 【原创】从 列表的重复 到 用sum展开二层嵌套列表将子元素合并

      转载请注明出处:https://www.cnblogs.com/oceanicstar/p/9517159.html     ★像R语言里头有rep函数可以让向量的值重复,在python里面可以直 ...

  3. 发送post请求几种常见content-type类型

    application/x-www-form-urlencoded 这应该是最常见的 POST 提交数据的方式了.浏览器的原生 form 表单,如果不设置 enctype 属性,那么最终就会以 app ...

  4. Java学习笔记十:Java的数组以及操作数组

    Java的数组以及操作数组 一:什么是数组: 数组可以理解为是一个巨大的“盒子”,里面可以按顺序存放多个类型相同的数据,比如可以定义 int 型的数组 scores 存储 4 名学生的成绩 数组中的元 ...

  5. 《史上最简单的MySQL教程》系列分享专栏

    <史上最简单的MySQL教程>系列分享专栏 <史上最简单的MySQL教程>已整理成PDF文档,点击可直接下载至本地查阅https://www.webfalse.com/read ...

  6. 关于JUnit4无法支持多线程测试的解决方法

    转自:https://segmentfault.com/a/1190000003762719 其实junit是将test作为参数传递给了TestRunner的main函数.并通过main函数进行执行. ...

  7. HyperLedger Fabric 1.4 架构(6.2)

    6.2.1 架构演进       Fabric架构经历了0.6版本到1.0版本的演进,架构上进行了重大改进,从0.6版本的结构简单演进到可扩展.多通道的设计,在架构上有了质的飞跃:从1.0版本以后,架 ...

  8. 开学测试之——ATM

    ---恢复内容开始--- package ATM;   //信1705-2 20173568 李泽宇   import java.util.*; import java.io.File; import ...

  9. java入门---基础语法&基础常识&编码规范&命名规范

        一个Java程序可以认为是一系列对象的集合,而这些对象通过调用彼此的方法来协同工作.下面简要介绍下类.对象.方法和实例变量的概念. 对象:对象是类的一个实例,有状态和行为.例如,一条狗是一个对 ...

  10. MySQL共享表空间扩容

    一.什么是共享表空间和独占表空间 共享表空间以及独占表空间都是针对数据的存储方式而言的. 共享表空间: 某一个数据库的所有的表数据,索引文件全部放在一个文件中,默认这个共享表空间的文件路径在data目 ...