lock详细解说请参考:Java多线程系列–“JUC锁”01之 框架
用10个线程读取10次商品信息,用3个线程修改商品价格;
使用lock接口来实现同步,方式和使用synchronized的方式差不多。lock.lock() 和 lock.unlock() 来创建一个临界区,和 synchronized的代码块类似;只不过换了一种方式。
代码如下:
public class Client {
public static void main(String[] args) {
final GoodInfo gi = new GoodInfo();
Thread[] read = new Thread[10]; //读线程,读取10次商品信息
for (int i = 0; i < 10; i++) {
read[i] = new Thread(new Runnable() {
@Override
public void run() {
gi.getInfo();
}
});
}
final Thread[] write = new Thread[3]; //写线程,修改3次价格
for (int i = 0; i < 3; i++) {
write[i] = new Thread(new Runnable() {
@Override
public void run() {
gi.setPrice(19);
}
});
}
for (Thread t : read) {
t.start();
}
for (Thread t : write) {
t.start();
}
}
}
/** 商品信息类 */
class GoodInfo {
private String name = "苹果"; //商品名称
private double price = 10; //商品价格
private final Lock lock = new ReentrantLock();
/**
* 读取商品信息
*
* @return
*/
public String getInfo() {
lock.lock();
try {
String name = this.name;
double price = this.price;
System.out.println(Thread.currentThread().getName() + "线程获取了商品信息:" + name + ":" + price);
return name + ":" + price;
} finally { //如果临界区内代码有异常需要try,记得一定要把释放锁的操作,放在finally中,防止程序出错,而没有释放锁,造成死锁
lock.unlock();
}
}
/**
* 修改商品价格
*
* @param price
*/
public void setPrice(double price) {
lock.lock();
try {
this.price = price;
System.out.println("--------------" + Thread.currentThread().getName() + "线程修改了商品价格:" + name + ":" + price);
} finally {
lock.unlock();
}
}
}
某一次的运行结果:
Thread-0线程获取了商品信息:苹果:10.0
Thread-7线程获取了商品信息:苹果:10.0
Thread-1线程获取了商品信息:苹果:10.0
Thread-9线程获取了商品信息:苹果:10.0
Thread-3线程获取了商品信息:苹果:10.0
--------------Thread-10线程修改了商品价格:苹果:19.0
Thread-2线程获取了商品信息:苹果:19.0
--------------Thread-12线程修改了商品价格:苹果:19.0
Thread-4线程获取了商品信息:苹果:19.0
Thread-5线程获取了商品信息:苹果:19.0
Thread-6线程获取了商品信息:苹果:19.0
Thread-8线程获取了商品信息:苹果:19.0
--------------Thread-11线程修改了商品价格:苹果:19.0
修改上面的程序代码:使用tryLock 来获取锁,如果没有获取到,则不执行正常的修改和获取商品信息操作,并打印出没有获取锁的线程
public class Client {
public static void main(String[] args) {
final GoodInfo gi = new GoodInfo();
Thread[] read = new Thread[10]; //读线程,读取10次商品信息
for (int i = 0; i < 10; i++) {
read[i] = new Thread(new Runnable() {
@Override
public void run() {
gi.getInfo();
}
});
}
final Thread[] write = new Thread[3]; //写线程,修改3次价格
for (int i = 0; i < 3; i++) {
write[i] = new Thread(new Runnable() {
@Override
public void run() {
gi.setPrice(19);
}
});
}
for (Thread t : read) {
t.start();
}
for (Thread t : write) {
t.start();
}
}
}
/** 商品信息类 */
class GoodInfo {
private String name = "苹果"; //商品名称
private double price = 10; //商品价格
private final Lock lock = new ReentrantLock();
/**
* 读取商品信息
*
* @return
*/
public void getInfo() {
if(lock.tryLock()) {
try {
String name = this.name;
double price = this.price;
System.out.println(Thread.currentThread().getName() + "线程获取了商品信息:" + name + ":" + price);
} finally { //记得一定要把释放锁的操作,放在finally中,防止程序出错,而没有释放锁,造成死锁
lock.unlock();
}
}else{
System.out.println("*************" + Thread.currentThread().getName() + "没有获取到锁");
}
}
/**
* 修改商品价格
*
* @param price
*/
public void setPrice(double price) {
if(lock.tryLock()){
try {
this.price = price;
System.out.println("--------------" + Thread.currentThread().getName() + "线程修改了商品价格:" + name + ":" + price);
} finally {
lock.unlock();
}
}else{
System.out.println("………………………………………………" + Thread.currentThread().getName() + "没有获取到锁");
}
}
}
某一次运行结果:
*************Thread-1没有获取到锁
*************Thread-5没有获取到锁
*************Thread-4没有获取到锁
*************Thread-3没有获取到锁
*************Thread-7没有获取到锁
………………………………………………Thread-12没有获取到锁
………………………………………………Thread-10没有获取到锁
Thread-9线程获取了商品信息:苹果:10.0
*************Thread-8没有获取到锁
*************Thread-6没有获取到锁
--------------Thread-11线程修改了商品价格:苹果:19.0
Thread-2线程获取了商品信息:苹果:19.0
Thread-0线程获取了商品信息:苹果:19.0
ReadWriteLock 是一个单独的接口,但是里面的writer和reader锁实现lock接口
ReadWriteLock 维护了一对相关的锁,一个用于只读操作,另一个用于写入操作。只要没有 writer,读取锁可以由多个 reader 线程同时保持。写入锁是独占的。
与互斥锁相比,读-写锁允许对共享数据进行更高级别的并发访问。虽然一次只有一个线程(writer 线程)可以修改共享数据,但在许多情况下,任何数量的线程可以同时读取共享数据(reader 线程),读-写锁利用了这一点。从理论上讲,与互斥锁相比,使用读-写锁所允许的并发性增强将带来更大的性能提高。在实践中,只有在多处理器上并且只在访问模式适用于共享数据时,才能完全实现并发性增强。
锁机制的最大改进之一就是ReadWriteLock 接口和它唯一的实现类ReentrantReadWriteLock,该类有两个内部类:WriteLock和ReadLock,使用ReadLock读操作锁时,可以由多个线程同时访问,而使用WriteLock操作锁时,其他线程不能够执行读操作。这样一来,就改进了性能,不用读取的时候每个线程都等待。
修改上面的示例:使用读写分离的锁来提高性能;如果统计下运行时间
public class Client {
public static void main(String[] args) {
final GoodInfo gi = new GoodInfo();
Thread[] read = new Thread[10]; //读线程,读取10次商品信息
for (int i = 0; i < 10; i++) {
read[i] = new Thread(new Runnable() {
@Override
public void run() {
gi.getInfo();
}
});
}
final Thread[] write = new Thread[3]; //写线程,修改3次价格
for (int i = 0; i < 3; i++) {
write[i] = new Thread(new Runnable() {
@Override
public void run() {
gi.setPrice(19);
}
});
}
for (Thread t : read) {
t.start();
}
for (Thread t : write) {
t.start();
}
}
}
/** 商品信息类 */
class GoodInfo {
private String name = "苹果"; //商品名称
private double price = 10; //商品价格
private final ReadWriteLock lock = new ReentrantReadWriteLock();
/**
* 读取商品信息
*
* @return
*/
public void getInfo() {
lock.readLock().lock();
try {
String name = this.name;
double price = this.price;
System.out.println(Thread.currentThread().getName() + "线程获取了商品信息:" + name + ":" + price);
} finally { //记得一定要把释放锁的操作,放在finally中,防止程序出错,而没有释放锁,造成死锁
lock.readLock().unlock();
}
}
/**
* 修改商品价格
*
* @param price
*/
public void setPrice(double price) {
lock.writeLock().lock();
try {
this.price = price;
System.out.println("--------------" + Thread.currentThread().getName() + "线程修改了商品价格:" + name + ":" + price);
Thread.sleep(200);
} catch (Exception e) {
} finally {
lock.writeLock().unlock();
}
}
}
待续。。
版权声明:本文为博主原创文章,未经博主允许不得转载。
[笔记][Java7并发编程实战手册]2.5使用Lock实现同步
原文地址:http://blog.csdn.net/mr_zhuqiang/article/details/47376725