并发执行和并行执行的区别:并行执行是指两个或多个事件在同一时刻发生,而并发执行是指两个或多个事情在同一时间间隔内发生。并发执行在宏观层面上看,事情之间是同时发生的。比如说在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;
}
@Override
public void run() {
while(true)
resource.productor();
}
}
static class HandlerTask implements Runnable{
private Resource2 resource;
public HandlerTask(Resource2 resource){
this.resource = resource;
}
@Override
public void run() {
while(true)
resource.customer();
}
}
}