首先使用Synchronized同步代码块可以实现生产者和消费者之间每一次的完整步骤,就好比银行家算法中的取钱步骤,如果没有synchronized同步代码块,可能会出现取钱1次对总共的金额减少,但是还没有来的及打印出来剩余金额,第二个线程中第二个用户对同一个账户再次进行取款,取款结束未进行打印时线程二暂停,开始执行线程一的打印,会导致数据发生错乱。
为了解决这个问题,我们可以在synchronized的前提下。引入了wait()和notify()的方法,如果某个条件未达到时,该线程使用wait()方法进行等待,当线程2达到该条件,使用notify()进行通知其他线程,这样可以防止数据与实际问题不符合的情况。这种情况对应生产者和消费者,生产者生产商品,生产一次消费者取一次产品,消费者取一次生产者才能继续生产。(一生产者一消费者的问题)。
/*这种判断条件: 如果flag是食物有无的标识符,如果为true就说明还有商品,此时
生产者不工作,消费者开始工作,当吃完食物时,将标志符置为false,此时生产者进行工作*/
public void run() {
for(int i=0;i<20;i++){
synchronized (food){
if(food.flag==false){
try {
food.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
food.setFood("屎");
System.out.println(Thread.currentThread().getName()+"正在吃"+food.getFood()+"你看他吃的很舒服");
food.notify();
food.flag=false;
}
}
}
如果我们面对(多生产者多消费者的问题),当判断条件还为if语句时如果没有达到我们想要的条件时,我们的思路是暂停该线程,notify()或者notifyAll()其他的线程。来进行继续执行,但是大家有没有想过这个问题,此时我暂停的只是一个生产者的线程,但是notify的是其他线程,是不是有可能也唤醒其他的生产者线程,如果我判断这个商品数量为10的时候,生产者线程就不生产了,但是我此时只是wait了一个生产者线程,随机唤醒其他线程,是不是有可能唤醒除了这个生产者线程的其他生产者线程?所以,此时我们就不能用这种方法进行修改了,我们需要用while的方法来对条件进行判断,不能用if条件进行判断了。
/*使用while进行判断*/
public synchronized void creatfood( String foodname){
while(list.size()==10){//通过while循环把所有的生产者线程全部的wait了
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
list.add(foodname);
System.out.println(Thread.currentThread().getName()+"拉了一吨"+foodname+"\t目前的"+foodname+"有"+list.size()+"吨");
this.notify();
}
多生产者多消费者:面对这个问题我们还可以使用Lock锁,synchrnized是自动上锁和解锁,但是lock锁我们必须手动上锁,手动开锁,所以必须使用try catch fianlly语句,不管怎么样,finally里是开锁语句。所以在这个问题中,我们还可以使用锁,来对这个进行控制,面对多生产者和多消费者,我们还能够对锁增加两种情况来进行使用。
private Lock lock=new ReentrantLock();//创建一个锁的对象
Condition makecond=lock.newCondition();//锁对象中的生产者
Condition eatcond=lock.newCondition();
创建好之后我们如何使用呢,只需要当遇到某个条件时指名道姓的告诉当某个锁,你们这种类型的稍微等一下,那么这种类型的都进入暂停的状态了,另一种类型的就当然可以运行了,同理,当另一种情况就时达到某种情况的时候,就告诉这种类型的锁。你们这种类型的锁需要等下,那么另一种锁便会开始运行。
public void creatfood( String foodname){
lock.lock();
try{
while(list.size()==10){
try {
makecond.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
list.add(foodname);
System.out.println(Thread.currentThread().getName()+"拉了一吨"+foodname+"\t目前的"+foodname+"有"+list.size()+"吨");
eatcond.signal();
}finally {
lock.unlock();
}
}
public synchronized void eatfood(){
lock.lock();
try{
while(list.size()==0){
try {
eatcond.await();//如果没得了,吃的就等等
} catch (InterruptedException e) {
e.printStackTrace();
}
}
list.remove(0);
System.out.println(Thread.currentThread().getName()+"吃了一口"+foodname+"\t目前的"+foodname+"有"+list.size()+"吨");
makecond.signalAll();//如果吃了一次,就通知生产者
}finally {
lock.unlock();
}
}
使用LOCK锁 !!!!必须必须要try catch finally语句来对锁进行手动的释放!!!111