Java 锁

1、Lock 接口常用方法

方法摘要

 void

lock() 
    获取锁(阻塞的方法,如果,不能获取锁一直进入阻塞的状态,直到获得锁。)

 boolean

tryLock() 
    仅在调用时锁为空闲状态才获取该锁。(非阻塞的方法,如果,不能获取锁,就返回false。)

 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、其他锁方法介绍

  WriteLock  writeLock=new ReentrantReadWriteLock().writeLock();

 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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值