synchronized和ReentrantLock实现消费者生产者问题

来源:互联网 发布:微分销系统源码开发 编辑:程序博客网 时间:2024/05/29 09:57

并发执行和并行执行的区别:并行执行是指两个或多个事件在同一时刻发生,而并发执行是指两个或多个事情在同一时间间隔内发生。并发执行在宏观层面上看,事情之间是同时发生的。比如说在2秒的时间内发生的两件事情,在历史的角度上可以看作是“同时发生”的。

在Java中,多个线程对临界区资源操作时,需要保持程序的可再现性,或者说内存可见性。不管哪个线程操作了临界资源,操作的结果都应该对下一个操作该资源的线程可见。我们需要通过线程间的同步机制来实现程序的可再现性。在Java中有两种方法实现:1.使用synchronized关键字  2.使用ReentrantLock对象

对于synchronized可以使用同步方法或者同步代码块的方式。使用这种方法,我们需要给定一个锁对象。

public class Resource2 {// count为临界资源private int count;//flag标记是否是应该生产还是消费private boolean flag = false;public int getCount() {return count;}public void setCount(int count) {this.count = count;}public void productor() {synchronized (this) {while (!flag) {try {wait();} catch (InterruptedException e) {e.printStackTrace();}}count++;System.out.println(Thread.currentThread().getName() + "。。。。。生产。。。。"+ count);flag = false;notifyAll();}}public void customer() {synchronized (this) {while (flag) {try {wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(Thread.currentThread().getName()+ "。。。。。。。。。。。消费。。。。。。。。" + count);flag = true;notifyAll();}}}

这里使用了同步代码块,注意的是wait()方法和notifyAll()方法是锁调用的。因为锁的状态由系统在维护,所以锁被释放的时候,只有它自己知道。这里使用的是对象本身。当然啦,可以直接在方法上加synchronized,这里默认的锁仍然是对象本身,但是当方法是静态的时候则是对象的字节码对象,即 类名.Class。notify方法是从线程池中唤醒其中一个线程,notifyAll很明显是把所有的线程都唤醒。很明显这里要用notifyAll,如果使用notify则可能会出现死锁的状况。假如前一个wait的是生产者,而notify唤醒的签好也是生产者线程,那么生产的东西无法被消费,所以会一直等待....

我们来介绍第二种方式,对于ReentrantLock,你需要自己创建锁,上锁然后释放锁。这会在某些情况下带给我们很好的处理,我们可以自己进行出错时处理,而不像synchronized,由系统维护者,出错时只能由系统处理,一般是抛出异常或错误。而且ReentrantLock还提供了trylock(int timeout, Type),通过这个方法,你可以在线程无法获得锁的时候去执行其它的任务,而不是像synchronized那样,获取不到就会一直等待着。这个方法该怎么唤醒其它线程呢,是不是跟synchronized那样使用锁的wait()和notify()或者notifyAll()呢?当然不是啦。ReentrantLock只是提供了锁,而锁的释放或者上锁是的状态是要通过ReentrantLock的内部类Condition来监视的。说白了Condition就是锁的一个监视器,同一把锁可以定义多组监视器,这样在分工的时候就不需要唤醒所有的线程,而是唤醒所需职能的线程。对于生产者消费者我们可以定义两组监视器,分别监听这两种分工线程。当然啦,锁由你创建并操作,那么你操作完了应该释放它,不然会出大问题。为了保证锁的释放,肯定在finally中进行啦。

public class Resource{//count为临界资源private int count;private boolean flag = true;//锁private ReentrantLock lock;//两组监视器private Condition proCondition;private Condition cusCondition;public Resource(){lock = new ReentrantLock();proCondition = lock.newCondition();cusCondition = lock.newCondition();}public Resource(int count){this.count = count;lock = new ReentrantLock();proCondition = lock.newCondition();cusCondition = lock.newCondition();}public int getCount() {return count;}public void setCount(int count) {this.count = count;}public  void productor(){lock.lock();try {while(!flag){try {proCondition.await();} catch (InterruptedException e) {e.printStackTrace();}}count++;System.out.println(Thread.currentThread().getName()+"。。。。。生产。。。。"+count);flag = false;cusCondition.signal();}finally{lock.unlock();}}public void customer(){lock.lock();try {while(flag){try {cusCondition.await();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(Thread.currentThread().getName()+"。。。。。。。。。。。消费。。。。。。。。"+count);flag = true;proCondition.signal();}finally{lock.unlock();}}}

最后定义两个任务

public class MainActivity {public static void main(String[] args) {Resource2 resource2 = new Resource2();ResourceTask proTask = new ResourceTask(resource2);HandlerTask cusTask = new HandlerTask(resource2);Thread proThread1 = new Thread(proTask);Thread proThread2 = new Thread(proTask);Thread cusThread3 = new Thread(cusTask);Thread cusThread4 = new Thread(cusTask);proThread1.start();proThread2.start();cusThread3.start();cusThread4.start();}static class ResourceTask implements Runnable{private Resource2 resource;public ResourceTask(Resource2 resource){this.resource = resource;}@Overridepublic void run() {while(true)resource.productor();}}static class HandlerTask implements Runnable{private Resource2 resource;public HandlerTask(Resource2 resource){this.resource = resource;}@Overridepublic void run() {while(true)resource.customer();}}}








0 0
原创粉丝点击