您的位置:首页 > 编程语言 > Java开发

Java并发之读写锁Lock和条件阻塞Condition的应用(转载)

2012-09-13 20:46 615 查看
Java 5中提供了另一种实现线程同步或互斥的机制,即使用Lock和Condition。

Lock比传统线程模型中的synchronized方式更加面向对象,也提供了更多可选择的锁机制。与生活中的锁类似,锁本身也是一个对象。两个线程执行的代码片段要实现同步互斥的效果,它们必须使用同一个Lock对象。锁是上在代表要操作的资源的类的内部方法中,而不是线程代码中。

Lock使用示例:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

// An example of using Lock.
public class LockTest {

public static void main(String[] args) {
new LockTest().init();

}

private void init() {
final Outputer outputer = new Outputer();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(10);

} catch(InterruptedException e) {
e.printStackTrace();

}
outputer.output("aaaaaaaaaaa");

}

}

}).start();

new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(10);

} catch(InterruptedException e) {
e.printStackTrace();

}
outputer.output("bbbbbbbbbbb");

}

}

}).start();

}

static class Outputer {
private Lock lock = new ReentrantLock();
public void output(String name) {
int len = name.length();
lock.lock();
try {
for (int i = 0; i < len; i++) {
System.out.print(name.charAt(i));

}
System.out.println();

} finally {
lock.unlock();

}

}

}

}


读写锁:分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,写锁与写锁互斥,这是由JVM控制的,我们只需要上好相应的锁即可。如果代码只读数据,可以很多人同时读,但不能同时写,那就上读锁;如果代码修改数据,只能有一个人在写,并不能同时读取,那就上写销锁。总之,读的时候上读锁,写的时候上写锁。

Java读写锁示例:

import java.util.Random;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockTest {
public static void main(String[] args) {
final MyQueue queue = new MyQueue();
for (int i = 0; i < 3; i++) {
new Thread() {
public void run() {
while (true) {
queue.get();
}
}

}.start();

new Thread() {
public void run() {
while (true) {
queue.put(new Random().nextInt(10000));
}
}

}.start();
}

}
}

class MyQueue {
// 共享数据,只能有一个线程能写该数据,但可以有多个线程同时读该数据。
private Object data = null;
ReadWriteLock  rwl  = new ReentrantReadWriteLock();

public void get() {
rwl.readLock().lock();
try {
System.out.println(Thread.currentThread().getName()
+ " be ready to read data!");
Thread.sleep((long) (Math.random() * 1000));
System.out.println(Thread.currentThread().getName()
+ "have read data :" + data);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
rwl.readLock().unlock();
}
}

public void put(Object data) {

rwl.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName()
+ " be ready to write data!");
Thread.sleep((long) (Math.random() * 1000));
this.data = data;
System.out.println(Thread.currentThread().getName()
+ " have write data: " + data);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
rwl.writeLock().unlock();
}
}

}


使用

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

// Using a ReadWriteLock to implement a cache.
public class CacheDemo {

private Map < String,
Object > cache = new HashMap < String,
Object > ();
private ReadWriteLock rwl = new ReentrantReadWriteLock();

public static void main(String[] args) {
CacheDemo cache = new CacheDemo();
Object obj = cache.getData("");
System.out.println(obj.toString());

}

// Get the value from DB if the value does not exist,and then return it.
public Object getData(String key) {
rwl.readLock().lock();
Object value = null;
try {
value = cache.get(key);
if (value == null) {
// Must release read lock before acquiring write lock
rwl.readLock().unlock();
rwl.writeLock().lock();
try {
// Recheck state because another thread might have acquired
// write lock and changed state before we did.
if (value == null) {
// Here may access Database.
// ...
value = "Data";

}

} finally {
rwl.writeLock().unlock();

}
rwl.readLock().lock();

}

} finally {
rwl.readLock().unlock();

}
return value;

}

}




Condition的功能类似在传统线程技术中的Object.wait和Object.notity的功能。在等待Condition时,允许发生“虚假唤醒”,这通常作为对基础平台语义的让步。对于大多数应用程序,这带来的实际影响很小,因为Condition应该总是在一个循环中被等待,并测试正被等待的状态声明。某个实现可以随意移除可能的虚假唤醒,但建议应用程序员总是假定这些虚假唤醒可能发生,因此总是在一个循环中等待。

一个锁内部可以有多个Condition,即有多路等待和通知,可以参看Jdk1.5提供的Lock和Condition实现的可阻塞队列的应用案例。在传统的线程机制中一个监视器对象上只能有一路等待和通知,要想实现多路等待和通知,必须嵌套使用多个同步监视器对象。

JDK文档中提供了一个很不错的示例(http://docs.oracle.com/javase/6/docs/api/ ),用Condition实现一个阻塞队列,代码如下:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class BoundedBuffer {
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();

final Object[] items = new Object[100];
int putptr,
takeptr,
count;

public void put(Object x) throws InterruptedException {
lock.lock();
try {
while (count == items.length)
notFull.await();
items[putptr] = x;
if (++putptr == items.length)
putptr = 0;
++count;
notEmpty.signal();

} finally {
lock.unlock();

}

}

public Object take() throws InterruptedException {
lock.lock();
try {
while (count == 0)
notEmpty.await();
Object x = items[takeptr];
if (++takeptr == items.length)
takeptr = 0;
--count;
notFull.signal();
return x;

} finally {
lock.unlock();

}

}

}


转载:http://blog.sina.com.cn/jiangafu
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: