在上文中提到了Lock接口以及对象,使用它,很优雅的控制了竞争资源的安全访问,但是这种锁不区分读写,称这种锁为普通锁。为了提高性能,Java提供了读写锁,在读的地方使用读锁,在写的地方使用写锁,灵活控制,在一定程度上提高了程序的执行效率。

Java中读写锁有个接口java.util.concurrent.locks.ReadWriteLock,也有具体的实现ReentrantReadWriteLock,详细的API可以查看JavaAPI文档。

下面这个例子是在文例子的基础上,将普通锁改为读写锁,并添加账户余额查询的功能,代码如下:

package cn.thread;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; /**
* 读写锁
*
* @author 林计钦
* @version 1.0 2013-7-25 上午10:33:37
*/
public class WriteReadLockTest {
public static void main(String[] args) {
WriteReadLockTest test = new WriteReadLockTest();
// 创建并发访问的账户
MyCount myCount = test.new MyCount("95599200901215522", 10000);
// 创建一个锁对象
ReadWriteLock lock = new ReentrantReadWriteLock(false);
// 创建一个线程池
ExecutorService pool = Executors.newFixedThreadPool(2);
// 创建一些并发访问用户,一个信用卡,存的存,取的取,好热闹啊
User u1 = test.new User("张三", myCount, -4000, lock, false);
User u2 = test.new User("张三他爹", myCount, 6000, lock, false);
User u3 = test.new User("张三他弟", myCount, -8000, lock, false);
User u4 = test.new User("张三", myCount, 800, lock, false);
User u5 = test.new User("张三他爹", myCount, 0, lock, true);
// 在线程池中执行各个用户的操作
pool.execute(u1);
pool.execute(u2);
pool.execute(u3);
pool.execute(u4);
pool.execute(u5);
// 关闭线程池
pool.shutdown();
} /**
* 信用卡的用户
*/
class User implements Runnable {
private String name; // 用户名
private MyCount myCount; // 所要操作的账户
private int iocash; // 操作的金额,当然有正负之分了
private ReadWriteLock myLock; // 执行操作所需的锁对象
private boolean ischeck; // 是否查询 User(String name, MyCount myCount, int iocash, ReadWriteLock myLock, boolean ischeck) {
this.name = name;
this.myCount = myCount;
this.iocash = iocash;
this.myLock = myLock;
this.ischeck = ischeck;
} public void run() {
if (ischeck) {
// 获取读锁
myLock.readLock().lock();
System.out.println("读:" + name + "正在查询" + myCount + "账户,当前金额为" + myCount.getCash());
// 释放读锁
myLock.readLock().unlock();
} else {
// 获取写锁
myLock.writeLock().lock();
// 执行现金业务
System.out.println("写:" + name + "正在操作" + myCount + "账户,金额为" + iocash + ",当前金额为"
+ myCount.getCash());
myCount.setCash(myCount.getCash() + iocash);
System.out.println("写:" + name + "操作" + myCount + "账户成功,金额为" + iocash + ",当前金额为"
+ myCount.getCash());
// 释放写锁
myLock.writeLock().unlock();
}
}
} /**
* 信用卡账户,可随意透支
*/
class MyCount {
private String oid; // 账号
private int cash; // 账户余额 MyCount(String oid, int cash) {
this.oid = oid;
this.cash = cash;
} public String getOid() {
return oid;
} public void setOid(String oid) {
this.oid = oid;
} public int getCash() {
return cash;
} public void setCash(int cash) {
this.cash = cash;
} @Override
public String toString() {
return "MyCount{" + "oid='" + oid + '\'' + ", cash=" + cash + '}';
}
}
}
写:张三正在操作MyCount{oid='95599200901215522', cash=10000}账户,金额为-4000,当前金额为10000
写:张三操作MyCount{oid='95599200901215522', cash=6000}账户成功,金额为-4000,当前金额为6000
写:张三他爹正在操作MyCount{oid='95599200901215522', cash=6000}账户,金额为6000,当前金额为6000
写:张三他爹操作MyCount{oid='95599200901215522', cash=12000}账户成功,金额为6000,当前金额为12000
写:张三正在操作MyCount{oid='95599200901215522', cash=12000}账户,金额为800,当前金额为12000
写:张三操作MyCount{oid='95599200901215522', cash=12800}账户成功,金额为800,当前金额为12800
写:张三他弟正在操作MyCount{oid='95599200901215522', cash=12800}账户,金额为-8000,当前金额为12800
写:张三他弟操作MyCount{oid='95599200901215522', cash=4800}账户成功,金额为-8000,当前金额为4800
读:张三他爹正在查询MyCount{oid='95599200901215522', cash=4800}账户,当前金额为4800

在实际开发中,最好在能用读写锁的情况下使用读写锁,而不要用普通锁,以求更好的性能。

Java多线程-新特征-锁(下)的更多相关文章

  1. Java多线程-新特征-锁

    Java中读写锁有个接口java.util.concurrent.locks.ReadWriteLock,也有具体的实现ReentrantReadWriteLock,详细的API可以查看JavaAPI ...

  2. Java多线程-新特征-锁(上)

    在Java5中,专门提供了锁对象,利用锁可以方便的实现资源的封锁,用来控制对竞争资源并发访问的控制,这些内容主要集中在java.util.concurrent.locks 包下面,里面有三个重要的接口 ...

  3. Java多线程-新特征-阻塞队列ArrayBlockingQueue

    阻塞队列是Java5线程新特征中的内容,Java定义了阻塞队列的接口java.util.concurrent.BlockingQueue,阻塞队列的概念是,一个指定长度的队列,如果队列满了,添加新元素 ...

  4. Java多线程-新特征-阻塞栈LinkedBlockingDeque

    对于阻塞栈,与阻塞队列相似.不同点在于栈是“后入先出”的结构,每次操作的是栈顶,而队列是“先进先出”的结构,每次操作的是队列头. 这里要特别说明一点的是,阻塞栈是Java6的新特征.. Java为阻塞 ...

  5. Java多线程-新特征-信号量Semaphore

    简介信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施, 它负责协调各个线程, 以保证它们能够正确.合理的使用公共资源. 概念Semaphore分为单值和多值两种,前者只能 ...

  6. Java多线程-新特征-原子量

    所谓的原子量即操作变量的操作是“原子的”,该操作不可再分,因此是线程安全的. 为何要使用原子变量呢,原因是多个线程对单个变量操作也会引起一些问题.在Java5之前,可以通过volatile.synch ...

  7. Java多线程并发08——锁在Java中的应用

    前两篇文章中,为各位带来了,锁的类型及锁在Java中的实现.接下来本文将为各位带来锁在Java中的应用相关知识.关注我的公众号「Java面典」了解更多 Java 相关知识点. 锁在Java中主要应用还 ...

  8. Java多线程系列--“JUC锁”08之 共享锁和ReentrantReadWriteLock

    概要 Java的JUC(java.util.concurrent)包中的锁包括"独占锁"和"共享锁".在“Java多线程系列--“JUC锁”02之 互斥锁Ree ...

  9. Java多线程系列--“JUC锁”03之 公平锁(一)

    概要 本章对“公平锁”的获取锁机制进行介绍(本文的公平锁指的是互斥锁的公平锁),内容包括:基本概念ReentrantLock数据结构参考代码获取公平锁(基于JDK1.7.0_40)一. tryAcqu ...

随机推荐

  1. Java方法

    所谓方法,就是用来解决一类问题的代码的有序组合,是一个功能模块. 一般情况下,定义一个方法的语法是: 其中: 1. 访问修饰符:方法允许被访问的权限范围, 可以是 public.protected.p ...

  2. s表达式和json表达式

    s表达式 + 1 2 3普通表达式 1+2+3json表达式{ +:[1, 2, 3]}优点,一个运算符,无限个参数 s表达式 * (+ 1 2) 3普通表达式 1+(2*3)json表达式{ *:[ ...

  3. git学习笔记12-标签管理-版本

    发布一个版本时,我们通常先在版本库中打一个标签(tag),这样,就唯一确定了打标签时刻的版本.将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来.所以,标签也是版本库的一个快照 ...

  4. Spring依赖注入

    依赖注入: 使用构造器注入 使用属性setter方法注入 使用Field注入(用于注解方式) 注入依赖对象可以采用手工装配或自动装配,在实际应用中建议使用手工装配,因为自动装配会产生未知情况,开发人员 ...

  5. mongoDB中的ID的生成原则

  6. MongoDB 权限

    1.使用mongod 启动后(加入了--auth后操作数据库则需要权限) mongod --dbpath=D:\mongdb\db --logpath=D:\mongodb\log.txt --por ...

  7. Java编程思想学习笔记_1(Java内存和垃圾回收)

    1.Java中对象的存储数据的地方: 共有五个不同的地方可以存储数据. 1)寄存器.最快,因为位于处理器的内部,寄存器按需求分配,不能直接控制. 2)堆栈.位于通用RAM,通过堆栈指针可以从处理器那里 ...

  8. (二)ubuntu学习前传—uboot常见命令

    1.uboot命令类似于linux行缓冲命令行,当我们向终端命令行输入命令的时候,这些命令没有立即被系统识别,而是被缓冲到一个缓存区(也就是系统认为我换没有输入完),当我们按下回车键(换行)后,系统就 ...

  9. 将一堆石子分成多堆——Multi-SG 游戏

    这类博弈只需要记住一点,一个由多个游戏组成的游戏sg值为这多个游戏的sg值异或和. 也就是所有对一整个nim游戏它的sg值即为每一小堆的sg的异或和. hdu 5795 这题就是可以选择把一堆石子分成 ...

  10. OpenGL的glRotatef旋转变换函数详解

    OpenGL的glRotatef旋转变换函数详解 先看一下函数定义:void glRotatef(GLfloat angle,  GLfloat x,     GLfloat y,     GLflo ...