java Lock & Condition, provide a similar, yet more extensive locking mechanism than synchronized,
Lock:
similar to the monitor lock used by synchronized, but more powerfull,
Condition:
bound to lock, provide methods similar to wait()/notify()/notifyAll() of Object,
------
class & interface
* Lock
interface of lock,
* ReentrantLock
basic implementation of Lock
*
* Condition
interface of condition,
*
* ReadWriteLock
interface, read/write version of Lock,
* ReentrantReadWriteLock
basic implementation of ReadWriteLock,
*
------
code
lock test:
package eric.j2se.concurrence.lockcondition;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Lock test
*
* @author eric
* @date Aug 14, 2012 8:04:57 PM
*/
public class LockTest {
private static int i;
private static Lock lk = new ReentrantLock();
public static void test() {
List<Thread> list = new ArrayList<Thread>();
int tcount = 3;
// prepare threads
for (int i = 0; i < tcount; i++) {
list.add(new Thread(new TmpRunnable(), "t-" + i));
}
// start threads
for (int i = 0; i < tcount; i++) {
list.get(i).start();
}
}
private static class TmpRunnable implements Runnable {
@Override
public void run() {
lk.lock();
try {
printTime("begin");
Thread.sleep(1000 * 1); // sleep a while, for test purpose
printTime("end");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lk.unlock();
}
}
}
public static void printTime() {
printTime("");
}
/**
* print thread name & time
*
* @param info
* additional info to print
*/
public synchronized static void printTime(String info) {
System.out.printf("%s:\t%d,\t,%d,\t%s\n", Thread.currentThread().getName(), ++i, System.currentTimeMillis() / 1000, info);
}
public static void main(String[] args) {
test();
}
}
condition test:
package eric.j2se.concurrence.lockcondition;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Condition test
*
* @author eric
* @date Aug 14, 2012 9:10:44 PM
*/
public class ConditionTest {
private static int i;
private static int bufSize = 26, size;
private static char cStart = 97;
private static char[] cbuf = new char[bufSize];
private static Lock lk = new ReentrantLock();
private static Condition cdEmpty = lk.newCondition();
private static Condition cdFull = lk.newCondition();
private static final int testInterval = 500; // interval of each step in milliseconds, for test
/**
* fill buffer, start when buffer is empty
*
* @throws InterruptedException
*/
public static void fill() throws InterruptedException {
lk.lock();
try {
while (size == bufSize) { // buffer is full, wait for condition empty
cdEmpty.await();
}
System.out.printf("\n\n------\nstart fill\n\n");
while (size < bufSize) { // buffer is not full now, fill it
char c = (char) (cStart + size);
cbuf[size++] = c;
printTime("put: " + new Character(c));
Thread.sleep(testInterval);
}
cdFull.signal(); // buffer is full filled now, need to be read
System.out.printf("\nbuffer full\n------\n\n");
} catch (Exception e) {
e.printStackTrace();
} finally {
lk.unlock();
}
}
/**
* take from buffer & empty it, start when buffer is full
*
* @throws InterruptedException
*/
public static void take() throws InterruptedException {
lk.lock();
try {
while (size != bufSize) { // not full, wait for condition full
cdFull.await();
}
System.out.printf("\n\n------\nstart take\n\n");
for (int i = 0; i < bufSize; i++) { // now is full, take
printTime("take: " + new Character(cbuf[i]));
size--;
Thread.sleep(testInterval);
}
cdEmpty.signal(); // buffer is empty now, need to be fill
System.out.printf("\nbuffer empty\n------\n\n");
} catch (Exception e) {
e.printStackTrace();
} finally {
lk.unlock();
}
}
public static void test() {
// thread to fill buffer
Thread tFill = new Thread(new Runnable() {
@Override
public void run() {
try {
while (true)
fill();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "t-fill");
// thread to take from buffer
Thread tTake = new Thread(new Runnable() {
@Override
public void run() {
try {
while (true)
take();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "t-take");
tTake.start();
tFill.start();
}
public static void printTime() {
printTime("");
}
/**
* print thread name & time
*
* @param info
* additional info to print
*/
public synchronized static void printTime(String info) {
System.out.printf("%s:\t%d,\t,%d,\t%s\n", Thread.currentThread().getName(), ++i, System.currentTimeMillis() / 1000, info);
}
public static void main(String[] args) {
test();
}
}
read/write lock test:
package eric.j2se.concurrence.lockcondition;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* Read Write Lock test
*
* @author eric
* @date Aug 14, 2012 10:34:08 PM
*/
public class ReadWriteLockTest {
private static int i;
private static ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private static Lock rlk = lock.readLock();
private static Lock wlk = lock.writeLock();
private static String data = "";
private static volatile long lastUpdate; // track last publish date
/**
* publish data, use write lock,
*
* @param newData
*/
public static void publish(String newData) {
wlk.lock();
try {
printTime("begin publish");
data = newData;
lastUpdate = System.currentTimeMillis(); // modify last update date
printTime("data:\n\t" + data);
printTime("end publish");
} catch (Exception e) {
e.printStackTrace();
} finally {
wlk.unlock();
}
}
/**
* view data, use read lock
*
* @param previousView
* last viewed publish date
* @return date of new publish, or -1 if no new publish
*/
public static long view(long previousView) {
if (previousView < lastUpdate) { // new publish
rlk.lock();
try {
printTime("view data:\n\t" + data);
} catch (Exception e) {
e.printStackTrace();
} finally {
rlk.unlock();
}
return lastUpdate;
} else { // no new publish
printTime("no new publish yet");
return -1;
}
}
public static void test() throws InterruptedException {
Thread tPublish = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
publish("hi, xxxxxx, data_" + i + "_xxxxxx");
try {
Thread.sleep(1000 * 10); // update interval
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}, "t-publish");
// prepare view threads
int tViewCount = 3; // count of view thread
List<Thread> tViewList = new ArrayList<Thread>();
final List<Long> tLastView = new ArrayList<Long>(); // keep track of last viewed publish date
for (int i = 0; i < tViewCount; i++) {
final int _index = i;
tViewList.add(new Thread(new Runnable() {
@Override
public void run() {
while (true) {
long _lastDate = view(tLastView.get(_index));
if (_lastDate > 0) {
tLastView.set(_index, _lastDate); // update last viewed publish date, if has new publish
}
try {
Thread.sleep(1000 * 4); // view interval
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}, "t-view-" + i));
tLastView.add(0L);
}
tPublish.start();
for (int i = 0; i < tViewCount; i++) {
tViewList.get(i).start();
Thread.sleep(1000 * 5); // start interval of view threads
}
}
public static void printTime() {
printTime("");
}
/**
* print thread name & time
*
* @param info
* additional info to print
*/
public synchronized static void printTime(String info) {
System.out.printf("%s:\t%d,\t,%d,\t%s\n", Thread.currentThread().getName(), ++i, System.currentTimeMillis() / 1000, info);
}
public static void main(String[] args) throws InterruptedException {
test();
}
}
------