Java5多线程---Lock
在Java5中的并发包java.util.concurrent.locks 下有个接口Lock ,这个接口是实现同步访问的另外一种形式,Lock为锁和等待条件提供一个框架的接口,它不同于内置同步和监视器。以前我们都是在用synchronized 关键字,用于修饰方法(同步方法)或者同步代码块来实现同步访问,在java5中我们可以用Lock来实现同步的访问。我们都知道用关键字synchronized修饰的方法或者synchronized代码块,当一个线程获取对应的监控器(对象锁)时候,并执行synchronized里面的代码的时候,其它线程会一直处于等待此线程释放监视器才有机会进行执行,此线程释放监视器有两种,一是此线程执行完毕,二是出现异常java虚拟机会让其自动释放监视器。
试想下在当前获取监视器的线程进行耗时的操作(如:进行IO操作或者直接说进行休眠),那么其它线程将无限的进行等待下去。synchronized方法或者 synchronized代码块执行完毕之后会自动释放监视器,而Lock需要用户自己手动释放,但lock 是更细粒度控制同步问题。
一、Lock
1、Lock是 java.util.concurrent.locks包下的一个接口,它实现提供了比使用synchronized方法和语句可获得的更广泛的锁定操作。锁变成了更加的灵活性,也带来了更多的责任。我们不使用块结构锁就事情了synchronized方法和代码块时会自动释放功能,大多数情况下,应该使用以下语句
Lock l = ...;
l.lock();
try {
// access the resource protected by this lock
} finally {
l.unlock();
}
锁定和取消锁定出现在不同的作用访问中时,必须谨慎地确保保持锁定时的所有执行的所有代码块用try-finally 货try-catch 加以保护,用于确保在必要时候释放锁的作用。所有Lock实现都必须实时与监视器锁提供的相同内存同步:成功的lock操作与成功的Lock操作具有相同的内存同步效应,成功的unlock操作与成功的Unlock操作具有相同的内存同步效应
void lock();
void lockInterruptibly();
Condition newCondition();
boolean tryLock();
boolean tryLock(long time,TimeUnit unit);
void unlock()
void lock() 方法获取锁,如果当前锁不可用,出于禁用当前的线程,并且在获得锁之前,该线程将处于休眠状态。unlock释放锁,当前持有监视器(锁)释放出来,让给其它线程持有机会具体用法代码如下:
package java5;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* lock的用法
* @author dongtian
* @date 2015年6月15日 下午3:49:27
*/
public class LockTest {
static Lock lock = new ReentrantLock();
private static class Thread1 extends Thread {
@Override
public void run() {
lock.lock();
System.err.println(Thread.currentThread().getName() +"获取锁");
try {
for (int i = 0; i < 10; i++) {
System.err.println("当前线程" +Thread.currentThread().getName());
Thread.currentThread().sleep(100);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
System.err.println(Thread.currentThread().getName() +"释放锁");
}
}
}
public static void main(String[] args) {
Thread1 thread1 = new Thread1();
Thread1 thread2 = new Thread1();
thread1.start();
thread2.start();
}
}
输出结果:是线程0执行10次,完成释放锁然后线程1获取锁执行10次然后释放锁
Thread-0获取锁
当前线程Thread-0
当前线程Thread-0
当前线程Thread-0
当前线程Thread-0
当前线程Thread-0
当前线程Thread-0
当前线程Thread-0
当前线程Thread-0
当前线程Thread-0
当前线程Thread-0
Thread-0释放锁
Thread-1获取锁
当前线程Thread-1
当前线程Thread-1
当前线程Thread-1
当前线程Thread-1
当前线程Thread-1
当前线程Thread-1
当前线程Thread-1
当前线程Thread-1
当前线程Thread-1
当前线程Thread-1
Thread-1释放锁
boolean tryLock()方法是尝试获取锁,是在仅在锁空闲状态才获取该锁并立即返回 (true) 否则返回false 如果没有获取空闲的锁则不会再次尝试,我们可以用一个循环轮询获取锁具体案例代码:
package java5;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* trylock的用法
* @author dongtian
* @date 2015年6月15日 下午3:49:27
*/
public class TryLock {
static Lock lock = new ReentrantLock();
private static class Thread1 extends Thread {
@Override
public void run() {
while (!lock.tryLock()) {
System.err.println("当前线程 "+ Thread.currentThread().getName() +" 正在尝试获取锁");
}
System.err.println("当前线程 "+ Thread.currentThread().getName() +" 获取锁成功!");
try {
for (int i = 0; i < 10; i++) {
System.err.println("当前线程" +Thread.currentThread().getName());
Thread.currentThread().sleep(100);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
System.err.println(Thread.currentThread().getName() +"释放锁");
}
}
}
public static void main(String[] args) {
Thread1 thread1 = new Thread1();
Thread1 thread2 = new Thread1();
thread1.start();
thread2.start();
}
}
输出结果:
当前线程 Thread-0 正在尝试获取锁
当前线程 Thread-0 获取锁成功!
当前线程 Thread-1 正在尝试获取锁
...
当前线程 Thread-1 正在尝试获取锁
当前线程 Thread-1 正在尝试获取锁
当前线程 Thread-1 正在尝试获取锁
当前线程 Thread-1 正在尝试获取锁
当前线程 Thread-1 正在尝试获取锁
当前线程 Thread-1 正在尝试获取锁
Thread-0释放锁
当前线程 Thread-1 获取锁成功!
当前线程Thread-1
当前线程Thread-1
当前线程Thread-1
当前线程Thread-1
当前线程Thread-1
当前线程Thread-1
当前线程Thread-1
当前线程Thread-1
当前线程Thread-1
当前线程Thread-1
Thread-1释放锁
boolean tryLock(long time,TimeUnit unit) 如果给定的锁在给定的时间内空闲,并且当前线程没有被中断,则可以获取该锁并立即返回,否则已经超过指定的等待的事件则会返回,此方法不会阻塞。具体方法如下:
package java5;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* trylock的用法
* @author dongtian
* @date 2015年6月15日 下午3:49:27
*/
public class TryLock {
static Lock lock = new ReentrantLock();
private static class Thread1 extends Thread {
@Override
public void run() {
try {
while (!lock.tryLock(1000,TimeUnit.SECONDS)) {
System.err.println("当前线程 "+ Thread.currentThread().getName() +" 正在尝试获取锁");
}
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.err.println("当前线程 "+ Thread.currentThread().getName() +" 获取锁成功!");
try {
for (int i = 0; i < 10; i++) {
System.err.println("当前线程" +Thread.currentThread().getName());
Thread.currentThread().sleep(100);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
System.err.println(Thread.currentThread().getName() +"释放锁");
}
}
}
public static void main(String[] args) {
Thread1 thread1 = new Thread1();
Thread1 thread2 = new Thread1();
thread1.start();
thread2.start();
}
}
输出结果如下:
当前线程 Thread-0 获取锁成功!
当前线程Thread-0
当前线程Thread-0
当前线程Thread-0
当前线程Thread-0
当前线程Thread-0
当前线程Thread-0
当前线程Thread-0
当前线程Thread-0
当前线程Thread-0
当前线程Thread-0
Thread-0释放锁
当前线程 Thread-1 获取锁成功!
当前线程Thread-1
当前线程Thread-1
当前线程Thread-1
当前线程Thread-1
当前线程Thread-1
当前线程Thread-1
当前线程Thread-1
当前线程Thread-1
当前线程Thread-1
当前线程Thread-1
Thread-1释放锁
lockInterrupt() 方法,如果当前线程未被中断,则获取锁。如果锁可用,则获取锁,并立即返回;如果锁不可用,出于线程调度目的,将禁用当前线程具体代码如下:
package java5;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* lock的用法
* @author dongtian
* @date 2015年6月15日 下午3:49:27
*/
public class LockInterruptTest {
static Lock lock = new ReentrantLock();
private static class Thread1 extends Thread {
@Override
public void run() {
System.err.println(Thread.currentThread().getName() +"获取锁");
try {
lock.lockInterruptibly();
for (int i = 0; i < 10; i++) {
System.err.println("当前线程" +Thread.currentThread().getName());
Thread.currentThread().sleep(100);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
System.err.println(Thread.currentThread().getName() +"释放锁");
}
}
}
public static void main(String[] args) {
Thread1 thread1 = new Thread1();
Thread1 thread2 = new Thread1();
thread1.start();
thread2.start();
}
}
package java5;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/***
*
* @author dongtian
* @date 2015年6月15日 下午4:48:56
*/
public class CachedData {
ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public void progress() {
readWriteLock.readLock().lock();
//读操作
String readData = reader.readLine();
readWriteLock.readLock().unlock();
readWriteLock.writeLock().lock();
write.write(readData);
readWriteLock.writeLock().unlock();
}
}
说明:如果一个线程占有读锁的时候,那么其它申请写锁会一直处于等待状态。