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

JDK1.5新特性——Lock、Condition接

2015-09-21 22:23 417 查看
        我们知道,多线程中往往会对同一资源数据进行操作,这就意味着需要同步处理。
        同步处理的过程:某线程拿到锁,持有锁,进行数据操作,释放锁。
        同步处理的原则:保证对数据操作的完整性。

        以往我们用synchronized修饰函数或定义synchronized语句块来实现同步处理的过程,我们只需要定义怎么处理数据就行了,而不考虑锁什么时候锁上、什么时候打开。同步函数的锁往往是本类对象的this引用或本类的字节码对象。

        而在JDK1.5中,提供了一种锁处理机制,即Lock、Condition接口。这里需要手动上锁、手动开锁。
        而且新特性更加的灵活。举个例子,在多生产多消费的线程中,我们用while循环来判断,用notifyAll()来唤醒所有的线程,那么不能只单单唤醒对方阵营中某一线程吗?而利用Lock、Condition是能实现的。

        这两个接口都是在java.util.concurrent.locks下的,所有使用时需要导包。

1
接口Lock

1.1
方法

1.1.1 void
lock()

        获取锁。可以让别的线程无法执行已上锁的代码。

1.1.2 void
unlock()

        释放锁。允许别的线程访问此代码。

1.1.3 ConditionnewCondition()

        返回绑定到此Lock实例的新Condition实例。

1.2 实现Lock接口的类

1.2.1 ReentrantLock

        一个可重入的互斥锁Lock,它具有与使用synchronized方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大。
        Locklock = newReentrantLock();//父类引用指向子类对象。
        Condition condition =lock.newCondition();

2 接口Condition

2.1 方法

2.1.1 void
await() throws InterruptedException

        使当前线程进入阻塞(等待)状态。

2.1.2 void
signal()

        唤醒一个等待线程。

2.1.3 void
signalAll()

        唤醒所有等待线程。

3 使用方法

class Resource
{
//公共资源属性
boolean flag = true; //标记值
final Lock lock = new ReentrantLock(); //生产一个锁(父类引用指向子类对象)
final Condition condition = lock.newCondition();//用生成的锁Condition实例
//同一个锁可以有n个不同的Condition实例,分别对不同的线程起作用哦
void set(公共资源)
{
lock.lock();//加锁
try
{
if(!flag)          //多线程 用while判断
condition.await(); //满足条件,等待(等待前finally释放锁)
//对公共资源的操作(写操作,生产)
flag = false;
condition.signal();//唤醒其他线程      //多线程 用signalAll()唤醒全部线程
}
catch(InterruptedException e)
{//异常处理:1、try-catch处理 2、throws处理(如下)
}
finally
{
lock.unlock();//释放锁
}
}
void get() throws InterruptedException //异常处理:抛给调用者处理
{
lock.lock();
try
{
if(flag)
condition.await();
//对公共资源的操作(读操作,消费)
flag = true;
condition.signal();
}
finally
{
lock.unlock();
}
}
}

4 改写程序

4.1 改写单生产单消费的程序

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Goods
{
String name;
int id = 0;
boolean flag = true;
final Lock lock = new ReentrantLock();
final Condition condition = lock.newCondition();
void set(String name) throws InterruptedException
{
lock.lock();
try
{
if(!flag)
condition.await();
this.name = name;
id++;
System.out.println(Thread.currentThread().getName()+"--商品--"+name+"--"+id);
flag = false;
condition.signal();
}
finally
{
lock.unlock();
}
}
void get()
{
lock.lock();
try
{
if(flag)
condition.await();
System.out.println(Thread.currentThread().getName()+"--商品--"+name+"--"+id);			flag = true;
condition.signal();
}
catch(InterruptedException e)
{
}
finally
{
lock.unlock();
}
}
}
class SetGoods implements Runnable
{
private Goods goods;
public SetGoods(Goods goods)
{
this.goods = goods;
}
public void run()
{
int n = 500;
while(n-- > 0)
{
try
{
goods.set("汉堡");
}
catch(InterruptedException e)
{
}
}
}
}
class GetGoods implements Runnable
{
private Goods goods;
public GetGoods(Goods goods)
{
this.goods = goods;
}
public void run()
{
int n = 500;
while(n-- > 0)
goods.get();
}
}
public class Main
{
public static void main(String[] args)
{
Goods goods = new Goods();
new Thread(new SetGoods(goods), "A生产").start();
new Thread(new GetGoods(goods), "C消费").start();
}
}

4.2 改写多生产多消费的程序

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Goods
{
String name;
int id = 0;
boolean flag = true;
final Lock lock = new ReentrantLock();
final Condition condition = lock.newCondition();
void set(String name) throws InterruptedException
{
lock.lock();
try
{
while(!flag)
condition.await();
this.name = name;
id++;
System.out.println(Thread.currentThread().getName()+"--商品--"+name+"--"+id);
flag = false;
condition.signalAll();
}
finally
{
lock.unlock();
}
}
void get()
{
lock.lock();
try
{
while(flag)
condition.await();
System.out.println(Thread.currentThread().getName()+"--商品--"+name+"--"+id);			flag = true;
condition.signalAll();
}
catch(InterruptedException e)
{
}
finally
{
lock.unlock();
}
}
}
class SetGoods implements Runnable
{
private Goods goods;
public SetGoods(Goods goods)
{
this.goods = goods;
}
public void run()
{
int n = 500;
while(n-- > 0)
{
try
{
goods.set("汉堡");
}
catch(InterruptedException e) {}
}
}
}
class GetGoods implements Runnable
{
private Goods goods;
public GetGoods(Goods goods)
{
this.goods = goods;
}
public void run()
{
int n = 500;
while(n-- > 0)
goods.get();
}
}
public class Main
{
public static void main(String[] args)
{
Goods goods = new Goods();
new Thread(new SetGoods(goods), "A生产").start();
new Thread(new SetGoods(goods), "B生产").start();
new Thread(new GetGoods(goods), "C消费").start();
new Thread(new GetGoods(goods), "D消费").start();
}
}


新特性更加的灵活。举个例子,在多生产多消费的线程中,我们用while循环来判断,用notifyAll()来唤醒所有的线程,那么不能只单单唤醒对方阵营中某一线程吗?而利用Lock、Condition是能实现的。

        看4.2改写多生产多消费的程序,也没有体现出比synchronized更加灵活的地方来,依旧是唤醒所有的程序啊?

5 使用方法升级版

class Resource
{
//公共资源属性
boolean flag = true;
final Lock lock = new ReentrantLock();
final Condition conditionProduce = lock.newCondition(); //lock产生两个Condition对象
final Condition conditionConsume = lock.newCondition();
void set(公共资源)
{
lock.lock();
try
{
while(!flag)
conditionProduce.await();//是当前线程等待
//数据操作
flag = false;
conditionConsume.signal();//将对方阵营中的一个线程唤醒
}
catch(Exception e) {}
finally   //必执行代码块
{
lock.unlock();
}
}
void get()
{
lock.lock();
try
{
while(!flag)
conditionConsume.await();//是当前线程等待
//数据操作
flag = false;
conditionProduce.signal();//将对方阵营中的一个线程唤醒
}
catch(Exception e) {}
finally   //必执行代码块
{
lock.unlock();
}
}
}


一个lock实例产生两个Condition对象,分别对不同的线程加以标记,从而进行不同的操作。

6 你会再次改写多生产多消费的例子吗?

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