java线程(4)——线程同步的锁技术
同步
同步,字面来看,有点一起工作的意思。但在线程同步中,“同”意为协同、互相配合。
比如:
A、B两个线程,并不是说两个线程必须同时一起工作,而是说互相配合工作,在某个时间可能线程A要等线程B去工作,之后线程A才能继续工作。如果理解不了,可以参考java线程(2)——模拟生产者与消费者中的例子。
思考: 
为什么会有线程同步?上面例子中线程A为什么要等B工作之后才能继续工作?
在生产者和消费者的例子中,作为消费者,如果生产者还没生产,他就没办法消费只能等着,否则就会出现问题。同样,生产者也不能无止尽的生产,毕竟篮子的容量是有限的。
如果这个例子看不出来问题的严重性,我们可以想想银行取钱的例子,出现问题这后果就相当严重了。所以,多线程如果使用不当,很容易出现线程不安全的问题。尤其涉及同步问题时,一定要小心使用。
实现方式
主要有两种:synchronized和lock,前者被称为内置锁,后者叫外置锁。
关于这两者的不同之处,介绍之后再比较。
1、 synchronized关键字
在消费者和生产者的例子中,我们使用到了synchronized关键字,将篮子的“取”和“放”都做了限制,来实现线程同步。
2、lock
先来看一下他的接口定义,也是在包java.util.concurrent下。
package java.util.concurrent.locks;
public interface Lock {
  void lock();
  void lockInterruptibly() throws InterruptedException;
  boolean tryLock();
  void unlock();
  Condition newCondition();
}在上篇博客中介绍了一个使用synchronized关键字实现打印当前时间的方法,我们这里来修改一下。
   /**
     * 获得当前时间
     */
    public static void getTime() {
        lock.lock();
        try {
            System.out.println("1、进入获取时间方法=====");
            Date date = new Date();
            DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String time = format.format(date);
            System.out.println("2、" + Thread.currentThread().getName() + ":"
                    + time);
            System.out.println("3、获取时间成功=====");
            System.out.println();
        } finally {
            lock.unlock();
        }
    }
//调用
    static Lock lock=null;
    public static void main(String[] args) {
        lock = new ReentrantLock();
        for (int i = 0; i < 100; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    getTime();
                }
            }).start();
        }
    }结果同样满足条件:
读写锁
Lock中的另一个亮点就是对读写锁的支持。在读写锁中,把对共享资源的访问者划分为读者和写者,读者进行读访问,写者进行写操作。但是,一个读写锁同时能有一个或多个读者,但不能同时既有读者又有写者。
java中的类为ReadWriteLock,提供了读锁和写锁的方法,返回类型都是Lock
public interface ReadWriteLock {
    Lock readLock();
    Lock writeLock();
}举个例子:
在例子中,data为所要读写的数据,提供了读和写的方法。
    private Object data = null;// 共享数据
    /**
     * 读数据
     */
    public void get() {
        try {
          //准备数据
            System.out.println(Thread.currentThread().getName()
                    + " be ready to read data!");
            //sleep一段时间,主要为了更明显的体现出差别,无实际意义
            Thread.sleep((long) (Math.random() * 1000));
            //打印取出数据
            System.out.println(Thread.currentThread().getName()
                    + "have read data :" + data);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    /**
     * 写数据
     *
     * @param data
     */
    public void put(Object data) {
        try {
            System.out.println(Thread.currentThread().getName()
                    + " be ready to write data!");
            Thread.sleep((long) (Math.random() * 1000));
            this.data = data; // 给data赋值
            System.out.println(Thread.currentThread().getName()
                    + " have write data: " + data);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } 
    }执行结果:
从结果上看,当程序刚启动时,多个读写线程同时触发,等待执行。无法实现“多读”,也影响了写的操作。
那么,现在来看下加上读写锁之后的效果。
ReadWriteLock rwl = new ReentrantReadWriteLock();
    /**
     * 读数据
     */
    public void get(){
        rwl.readLock().lock(); //读锁
        try {
            ....略
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally{
            rwl.readLock().unlock(); //释放读锁
        }
    }与上面没有使用读写锁相比,最大的不同在于,他可以实现“多读”,并且“读”与“写”互斥。例如:Thread0,2,4进入之后,可以同时读数据。并没有多条写数据同时写。
点睛之笔
1)Lock与ReadWriteLock
以Lock第一个例子ReentrantLock来说,他实现了标准的互斥操作,有点“独占”的感觉。这种情况下,不允许多读,多写,读写等情况发生。
读写锁ReadWriteLock中,允许多个读线程同时访问一个资源,但不允许多个写线程同时访问。更符合实际操作和需要。
2)Lock与synchronized
synchronized比较武断,只能实现互斥,无法实现读写锁的允许多读操作。在并发量比较小的情况下,他是一个不错的选择。但并发量较大的话,他的性能下降很严重。
Lock锁技术除了第一点介绍的优点外,他还具有可重入性,即可以进行多次加锁,也更具公平性。不过为了避免死锁,需要在finally中释放锁。
java线程(4)——线程同步的锁技术的更多相关文章
- Java 虚拟机:互斥同步、锁优化及synchronized和volatile
		互斥同步 互斥同步(Mutual Exclusion & Synchronization)是常见的一种并发正确性保证手段.同步是指子啊多个线程并发访问共享数据时,保证共享数据在同一时刻只能被一 ... 
- Java多线程02(线程安全、线程同步、等待唤醒机制)
		Java多线程2(线程安全.线程同步.等待唤醒机制.单例设计模式) 1.线程安全 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果是一样的,而且其他的变量 ... 
- java  线程Thread 技术--线程状态与同步问题
		线程技术第三篇: 线程的状态: 1. 创建状态: 当用new 操作符创建一个新的线程对象时,该线程就处于创建状态,系统不为它分配资源 2.可运行状态:当线程调用start 方法将为线程分配必须的系统资 ... 
- Java基础学习笔记: 多线程,线程池,同步锁(Lock,synchronized )(Thread类,ExecutorService ,Future类)(卖火车票案例)
		多线程介绍 学习多线程之前,我们先要了解几个关于多线程有关的概念.进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 线 ... 
- JAVA语言规范-线程和锁章节之同步、等待和通知
		JAVA语言规范:线程和锁 1 同步 java编程语言提供了线程间通信的多种机制.这些方法中最基本的是同步化,此方法是使用监视器实现的.JAVA中每个对象与一个监视器相关联,一个线程可以加锁和解锁监视 ... 
- Java线程:线程的同步与锁
		一.同步问题提出 线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏. 例如:两个线程ThreadA.ThreadB都操作同一个对象Foo对象,并修改Foo对象上的数据. public ... 
- java线程(2)--同步和锁
		参考转载:http://rainyear.iteye.com/blog/1734311 http://turandot.iteye.com/blog/1704027 http://www.cnblog ... 
- Java多线程-线程的同步与锁
		一.同步问题提出 线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏.例如:两个线程ThreadA.ThreadB都操作同一个对象Foo对象,并修改Foo对象上的数据. package ... 
- (转)Java线程:线程的同步与锁
		Java线程:线程的同步与锁 一.同步问题提出 线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏. 例如:两个线程ThreadA.ThreadB都操作同一个对象Fo ... 
随机推荐
- c c++面试----c工程开发之链接
			多数c语言的初学者对c工程开发过程各个阶段的作用理解不到位,而这方面的的知识又是实际开发过程中经常用到的技能点,所以就成为面试考察中一个重要的考察方面.例如:头文件的作用.头文件的内容:链接的作用和意 ... 
- 转:java23种设计模式
			以下是学习过程中查询的资料,别人总结的资料,比较容易理解(站在各位巨人的肩膀上,望博主勿究) 概述 设计模式是针对某一类问题的最优解决方案,是从许多优秀的软件系统中总结出的. Java中设计模式(ja ... 
- jsonp 跨域只能调用一次ajax(无法多次调用或者循环调用)
			jsonp 跨域只能掉用一次ajax(无法多次调用或者循环调用) 百度搜索关键字:jsonp 只能调用一次ajax 解决方法 //回调函数设置,给后台执行 window[callback ... 
- CP-ABE ToolKit 安装笔记
			博主论文狗,好久没有来贴博客,最近做实验需要用到属性加密,了解了下CP-ABE,前来记录一下: 网上相关的博文较多,博主看了大部分的,认为下面这两个看完了基本就可以成功安装. 可参见博文: http: ... 
- memcached搭建
			MemCache 安装使用 安装memcached之前首先需要安装libevent, 如果没有安装的请自行去安装. 下载memcache http://www.memcached.org/files/ ... 
- 对bluebird的理解
			前言 Promise:把原来的回调写法分离出来,在异步操作执行完后,用链式调用的方式执行回调函数. 在公众号的开发里面用的const Promise = require('bluebird');con ... 
- 在Android studio中用gradle打 jar 包(Mac下)
			这两天公司要重构项目,以前的项目在eclipse上,准备迁移到Android studio上,需要对项目打包,于是我学习了Android studio中gradle打包的内容.我在公司用的Mac,在家 ... 
- Vue 去脚手架插件,自动加载vue文件
			接上回 一些本质 本质上,去脚手架也好,读取vue文件也好,无非是维护options,每个Vue对象的初始化配置对象不触及Vue内部而言,在外部想怎么改都是可以的,只要保证options的正确,一切都 ... 
- AWS安装CDH5.3-CentOS6.4中关键操作步骤
			1.在AWS masternode 上下载cloudera-manager-installer.bin安装包 [root@ip-172-21-42-114 ~]# wget http://archiv ... 
- JDBC剖析篇(2):JDBC之PreparedStatement
			一次有人问我为什么要使用JDBC中的PreparedStatement,我说可以“防止SQL注入”,其他的却不能说出个一二三,现在来看看其中的秘密 参考文章: http://www.jb51.net/ ... 
