java 多线程,在对统一变量进行操作的时候容易产生高并发现象,jdk1.5之前都是用synchronized关键字来处理,这个是jdk级别的锁,作用于方法和代码块是关键字,不用手动的去释放锁,是一种悲观reentrantlock是jdk1.5之后的一个更灵活的锁,但是需要在执行上锁以后进行手动释放锁,一般都是在finnally中进行释放锁,保证锁的释放。
reentrantlock,synchronized两个锁都是可重入锁,什么是可重入锁呢,就是线程已经持有来某个方法A的锁,方法A再调用B的时候同样可以给B加锁,两者都属于内置锁,所有的内置锁都是可重入锁,否则如果不可重入的话会造成死锁等待。
synchronized加锁的原理是,当使用此关键字的时候底层会有monitorenter命令和monitorexit,monitor监视器进行见识当monitorenter开始进入,那么线程进入数就变为1,当monitorexit开始进入那么线程进入数为0,当有重入锁的时候这个数会累加,退出的时候一样进行递减。
这里有个问题如果26行放开把20行注释,线程将不会停止,可以想一下为什么
package JUC;
public class TestProducerAndConsumer {
public static void main(String[] args){
Clerk clerk =new Clerk();
Productor productor =new Productor(clerk);
Consumer consumer =new Consumer(clerk);
new Thread(productor,"生产者A").start();;
new Thread(consumer,"消费者A").start();;
new Thread(productor,"生产者B").start();;
new Thread(consumer,"消费者B").start();;
}
}
class Clerk{
private int product =0;
/**
* 进货
*/
public synchronized void get() {
while (product >=10) {
System.out.println("产品已满");
try{
this.wait();
}catch (InterruptedException e){
}
}
System.out.println(Thread.currentThread().getName() +":" + ++product);
this.notifyAll();
}
/**
* 退货
*/
public synchronized void sale(){
while(product<=0){
System.out.println("缺货");
try{
this.wait();
}catch (InterruptedException e){
}
}
System.out.println(Thread.currentThread().getName()+":"+ --product);
this.notifyAll();
}
}
class Productorimplements Runnable{
private Clerkclerk;
Productor(Clerk clerk){
this.clerk = clerk;
}
@Override
public void run() {
for (int i=0;i<20;i++){
clerk.get();
}
}
}
class Consumerimplements Runnable{
private Clerkclerk;
Consumer(Clerk clerk){
this.clerk = clerk;
}
@Override
public void run() {
for (int i=0;i<20;i++){
clerk.sale();
}
}
}
这个例子是生产这消费这问题,如果将进货和退货里面的while改成if 则容易造成并发的问题,在jdk官方文档中有说明this.wait()建议在循环中调用,否则容易引起虚假唤醒。
我们同样可以尝试用lock 锁去替代synchronized,这个在这里就不详细的写了,只需要将object的线程唤醒和等待换成condition中的线程唤醒和等待方法就可以了