同步处理的过程:某线程拿到锁,持有锁,进行数据操作,释放锁。
同步处理的原则:保证对数据操作的完整性。
以往我们用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 你会再次改写多生产多消费的例子吗?