1、Lock 接口常用方法
方法摘要 | |
void | lock() |
boolean | tryLock() |
boolean | tryLock(long time, TimeUnit unit) |
void | unlock() |
| lockInterruptibly() 申请锁,这个锁可以响应中断 |
2、简单的锁的使用
参考(1)
/需要避免并发访问的帐户资源(互斥资源)
class MyCount
{
//表示帐户余额的成员变量
private int count;
//有参构造器
public MyCount(int count)
{
this.count=count;
}
//获取帐户余额的方法
public int getCount()
{
return count;
}
//设置帐户余额的方法
public void setCount(int count)
{
this.count=count;
}
}
//表示对帐户进行操作的用户对象
class MyUser implements Runnable
{
//表示用户名称的成员变量
private String userName;
//锁对象引用
private Lock countLock;
//帐户对象引用
private MyCount mc;
//取款或存款数额(正数表示存款,负数表示取款)
private int taskSum;
//有参构造器
public MyUser(String userName,Lock countLock,MyCount mc,int taskSum)
{
this.userName=userName;
this.countLock=countLock;
this.mc=mc;
this.taskSum=taskSum;
}
//表示任务的run方法
public void run()
{
//表示是否成功操作的标志
boolean okFlag=false;
while(!okFlag)
{//如果不成功则继续尝试操作
try
{
//获取帐户锁
countLock.lock();
if(taskSum<0)
{//取款的操作
if(taskSum+mc.getCount()>=0)
{//如果余额充足则取款
mc.setCount(mc.getCount()+taskSum);
System.out.println(userName+"成功取款"+(-taskSum)+"元,余额为:"
+mc.getCount()+"元。");
okFlag=true;
}
}
else
{//存款的操作
mc.setCount(mc.getCount()+taskSum);
System.out.println(userName+"成功村款"+taskSum+"元,余额为:"
+mc.getCount()+"元。");
okFlag=true;
}
}
finally
{
//释放帐户锁
countLock.unlock();
}
if(okFlag==true){break;}
try
{
System.out.println(userName+":余额不足,等待一段时间再试!!!");
//余额不足,等待一段时间再试
Thread.sleep(100);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
}
//主类
public class Mian
{
public static void main(String args[])
{
//创建帐户资源对象
MyCount mc=new MyCount(50);
//创建锁对象
Lock countLock=new ReentrantLock();
//创建线程池
ExecutorService threadPool= Executors.newFixedThreadPool(2);
//执行两个任务
threadPool.execute(new MyUser("User1",countLock,mc,-200));
threadPool.execute(new MyUser("User2",countLock,mc,200));
//关闭线程池
threadPool.shutdown();
}
}
运行结果:
3、中断锁。
如果发现该操作已经在执行,等待执行。这时可中断正在进行的操作立刻释放锁继续下一操作。
也就是可以在等待,
ReentrantLock 的lock机制有2种,忽略中断锁和响应中断锁,这给我们带来了很大的灵活性。比如:如果A、B2个线程去竞争锁,A线程得到了锁,B线程等待,但是A线程这个时候实在有太多事情要处理,就是一直不返回,B线程可能就会等不及了,想中断自己,不再等待这个锁了,转而处理其他事情。这个时候ReentrantLock 就提供了2种机制,第一,B线程中断自己(或者别的线程中断它),但是ReentrantLock 不去响应,继续让B线程等待,你再怎么中断,我全当耳边风(synchronized原语就是如此);第二,B线程中断自己(或者别的线程中断它),ReentrantLock 处理了这个中断,并且不再等待这个锁的到来,完全放弃。[参考(4)]
public class Test {
// 是用ReentrantLock,还是用synchronized
public static boolean useSynchronized = false;
public static void main(String[] args) {
IBuffer buff = null;
if (useSynchronized) {
buff = new Buffer();
} else {
buff = new BufferInterruptibly();
}
final Writer writer = new Writer(buff);
final Reader reader = new Reader(buff);
writer.start();
reader.start();
new Thread(new Runnable() {
public void run() {
long start = System.currentTimeMillis();
for (;;) {
// 等5秒钟去中断读
if (System.currentTimeMillis() - start > 5000) {
System.out.println("不等了,尝试中断");
reader.interrupt();
break;
}
}
}
}).start();
}
}
interface IBuffer {
public void write();
public void read() throws InterruptedException;
}
class Buffer implements IBuffer {
private Object lock;
public Buffer() {
lock = this;
}
public void write() {
synchronized (lock) {
long startTime = System.currentTimeMillis();
System.out.println("开始往这个buff写入数据…");
for (;;)// 模拟要处理很长时间
{
if (System.currentTimeMillis() - startTime > Integer.MAX_VALUE)
break;
}
System.out.println("终于写完了");
}
}
public void read() {
synchronized (lock) {
System.out.println("从这个buff读数据");
}
}
}
class BufferInterruptibly implements IBuffer {
private ReentrantLock lock = new ReentrantLock();
public void write() {
lock.lock();
try {
long startTime = System.currentTimeMillis();
// System.out.println("开始往这个buff写入数据…");
// for (;;)// 模拟要处理很长时间
// {
//
// if (System.currentTimeMillis() - startTime > Integer.MAX_VALUE)
// break;
// }
try {
Thread.sleep(500000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("终于写完了");
} finally {
lock.unlock();
}
}
public void read() throws InterruptedException {
lock.lockInterruptibly();// 注意这里,可以响应中断
try {
System.out.println("从这个buff读数据");
} finally {
lock.unlock();
}
}
}
class Writer extends Thread {
private IBuffer buff;
public Writer(IBuffer buff) {
this.buff = buff;
}
@Override
public void run() {
buff.write();
}
}
class Reader extends Thread {
private IBuffer buff;
public Reader(IBuffer buff) {
this.buff = buff;
}
@Override
public void run() {
try {
buff.read();
} catch (InterruptedException e) {
System.out.println("我不读了");
}
System.out.println("读结束");
}
}
本例子展示,锁的方法是可以响应中断。
ps:for的不断的循环的方法,cpu将要全部的占用。
4、其他锁方法介绍
ReadLock readLock= new ReentrantReadWriteLock().readLock();
我们知道在一般锁的封锁策略中,同时只能够有一个线程有锁运行。如果,只是锁的读,并没有必要锁,所以读写的锁的策略不同,同一时刻,可以多个线程拥有读的权利,然而只有一个线程拥有写的权利。
参考:
(1)http://item.jd.com/10062576.html
(2)ReentrantLock可重入锁的使用场景 http://my.oschina.net/noahxiao/blog/101558
(3)http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantLock.html
(4)ReentrantLock与synchronized的区别 ( byquqi99 ) http://blog.csdn.net/quqi99/article/details/5298017