源无极

导航

 

一、一生产一消费:操作值

        等待、通知模式最经典的案例是“生产者/消费者” 模式,但此模式

在使用上有几种变形,有一些小的注意事项,但原理都是wait/notify

package com.it.po.thread9;

public class P  {
private String lock;

    public P(String lock) {
        this.lock = lock;
    }
    public void setValue(){
            try {
                synchronized (lock) {
                    if(!ValueObject1.value.equals("")){//先等着
                        lock.wait();
                    }
                    String value=System.currentTimeMillis()+"_"+System.nanoTime();
                    System.out.println("set value= "+value);
                    ValueObject1.value=value;
                    lock.notify();//通知取值
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    }
}

 

package com.it.po.thread9;

public class S {
private String lock;
    public S(String lock) {
        this.lock = lock;
    }
    public void getValue(){
            try {
                synchronized (lock) {
                    if("".equals(ValueObject1.value)){//没值先等着
                        lock.wait();
                    }
                    System.out.println("get Value= "+ValueObject1.value);
                    ValueObject1.value="";
                    lock.notify();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    }
}

 

package com.it.po.thread9;
import java.util.ArrayList;
import java.util.List;
public class ValueObject1 {
public static String value="";
}

 

package com.it.po.thread9;
public class MyThread2_2 extends Thread {
private String lock;
    public MyThread2_2(String lock) {
        this.lock = lock;
    }
    @Override
    public void run() {
        super.run();
        while (true){
            new P(lock).setValue();
        }
    }
}

 

package com.it.po.thread9;
public class MyThread2_1 extends Thread {
private String lock;
    public MyThread2_1(String lock) {
        this.lock = lock;
    }
    @Override
    public void run() {
        super.run();
        while (true) {
            new S(lock).getValue();
        }
    }
}

 

package com.it.po.thread9;
public class Run6 {
    public static void main(String[] args) throws InterruptedException {
        String lock = "po";
        MyThread2_1 my1 = new MyThread2_1(lock);
        MyThread2_2 my2 = new MyThread2_2(lock);
        my2.start();
        my1.start();
    }

}

 

set value= 1574692190737_1636737500969725
get Value= 1574692190737_1636737500969725
set value= 1574692190737_1636737501017240
get Value= 1574692190737_1636737501017240
set value= 1574692190737_1636737501065834
get Value= 1574692190737_1636737501065834
set value= 1574692190737_1636737501114428
get Value= 1574692190737_1636737501114428
set value= 1574692190737_1636737501163563
get Value= 1574692190737_1636737501163563
set value= 1574692190737_1636737501213237
get Value= 1574692190737_1636737501213237

 二、多个生产者和多个消费者的情况

         以上是一个生产者和一个消费者,如果是多个生产者和多个消费者

则可能出现假死的情况,也就是多个线程出现waiting等待状态。

      如果全部线程进入waiting状态,那么程序就不再执行任何业务功能了。

整个项目呈停止状态

 (一)、假死状态

package com.it.po.thread9;
public class P2 {
private String lock;
    public P2(String lock) {
        this.lock = lock;
    }
    public void setValue(){
            try {
                synchronized (lock) {
                    while(!ValueObject1.value.equals("")){//先等着
                        System.out.println(Thread.currentThread().getName()+" waiting");
                        lock.wait();
                    }
                    System.out.println(Thread.currentThread().getName()+" runnable");
                    String value=System.currentTimeMillis()+"_"+System.nanoTime();
                    ValueObject1.value=value;
                    lock.notify();//通知取值
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    }
}
package com.it.po.thread9;
public class S2 {
private String lock;
    public S2(String lock) {
        this.lock = lock;
    }
    public void getValue(){
            try {
                synchronized (lock) {
                    while ("".equals(ValueObject1.value)){//没值先等着
                        System.out.println(Thread.currentThread().getName()+" waiting");
                        lock.wait();
                    }
                    System.out.println(Thread.currentThread().getName()+" running");
                    ValueObject1.value="";
                    lock.notify();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    }
}

 

 

 

 

 

package com.it.po.thread9;

public class Run7 {
    public static void main(String[] args) throws InterruptedException {
        String lock="lanpo";
        P2 p2 = new P2(lock);
        S2 s2 = new S2(lock);
         Thread3_1 my1 = new Thread3_1(p2);
         Thread3_2 my2 = new Thread3_2(p2);
         Thread3_3 my3 = new Thread3_3(s2);
         Thread3_4 my4 = new Thread3_4(s2);
         my1.setName("1 号 生产者");
         my2.setName("2 号 生产者");
         my3.setName("1 号 消费者");
         my4.setName("2 号 消费者");
         my1.start();
         my2.start();
         my3.start();
         my4.start();
         Thread.sleep(2000);
        Thread[] threads = new Thread[Thread.currentThread().getThreadGroup().activeCount()];
        Thread.currentThread().getThreadGroup().enumerate(threads);
        for(int i=0;i<threads.length;i++){
        System.out.println(threads[i].getName()+" "+threads[i].getState());
        }
    }

}

 

 

 

 

 四个线程都呈 假死状态(waiting)

 左边是序号:下面的前面数字都是序号

1.    1号消费者发现value为空,只能等,准备唤醒异类线程 1号生产者

2.    1号生产者生产完,放弃锁,但是run方法中是while 又马上获取锁,进入了

setValue 方法中的while 然后waiting

 3. 1号生产者唤醒同类线程生产者2号

。。。

同理分析到 8,9

10. 这一步是关键,在两个生产者都处于waiting的时候,消费者又唤醒同类

最终导致四个线程处于waiting。。。

 (二)、解决假死状态

 将notify 都变成notifyAll即可

package com.it.po.thread9;
public class S2 {
private String lock;
    public S2(String lock) {
        this.lock = lock;
    }
    public void getValue(){
            try {
                synchronized (lock) {
                    while ("".equals(ValueObject1.value)){//没值先等着
                        System.out.println(Thread.currentThread().getName()+" waiting");
                        lock.wait();
                    }
                    System.out.println(Thread.currentThread().getName()+" running");
                    ValueObject1.value="";
                    lock.notifyAll();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    }
}

 

package com.it.po.thread9;
public class P2 {
private String lock;
    public P2(String lock) {
        this.lock = lock;
    }
    public void setValue(){
            try {
                synchronized (lock) {
                    while(!ValueObject1.value.equals("")){//先等着
                        System.out.println(Thread.currentThread().getName()+" waiting");
                        lock.wait();
                    }
                    System.out.println(Thread.currentThread().getName()+" runnable");
                    String value=System.currentTimeMillis()+"_"+System.nanoTime();
                    ValueObject1.value=value;
                    lock.notifyAll();//通知取值
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    }
}

 

 

 程序一直运行。。。

 

三、一生产与多消费 操作栈

生产者向堆栈List对象中放入数据

使消费者从堆栈中List取数据List最大容量是1

(一)先看一生产者对一消费者

package com.it.po.thread10;
import java.util.ArrayList;
import java.util.List;
public class MyStack {
private List list =new ArrayList();
synchronized  public void push(){
    try {
        if(list.size()==1) {
            System.out.println(Thread.currentThread().getName() +" waiting");
            this.wait(); //this就是当前对象
        }
        System.out.println(Thread.currentThread().getName() +" runnable");
        list.add(System.nanoTime());
        this.notify();
        System.out.println("push  size() "+list.size());
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

    synchronized public void pop(){//取出
    try {
        if(list.size()==0) {
            System.out.println(Thread.currentThread().getName() +" waiting");
            this.wait();
        }
        System.out.println(Thread.currentThread().getName() +" runnable");
        list.remove(0);
        this.notify();
        System.out.println("pop  size() "+list.size());
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

}

 

 

 

package com.it.po.thread10;
import com.it.po.thread9.MyThread1_1;
import com.it.po.thread9.MyThread1_2;
import com.it.po.thread9.MyThread1_3;
import com.it.po.thread9.NotifyThread1_4;
public class Run1 {
    public static void main(String[] args) throws InterruptedException {
        MyStack myStack = new MyStack();
        Thread1_1 my1 = new Thread1_1(myStack);
        Thread1_2 my2 = new Thread1_2(myStack);
        my1.setName("生产者 ");
        my2.setName("消费者 ");
        my1.start();
        my2.start();


    }

}

 

消费者  waiting
生产者  runnable
push  size() 1
生产者  waiting
消费者  runnable
pop  size() 0
消费者  waiting
生产者  runnable
push  size() 1
生产者  waiting
消费者  runnable
pop  size() 0
消费者  waiting

 

一直执行。。。

 

(二)、一生产者对多个消费者

package com.it.po.thread10;
import com.it.po.thread9.MyThread1_1;
import com.it.po.thread9.MyThread1_2;
import com.it.po.thread9.MyThread1_3;
import com.it.po.thread9.NotifyThread1_4;
public class Run1 {
    public static void main(String[] args) throws InterruptedException {
        MyStack myStack = new MyStack();
        Thread1_1 my1 = new Thread1_1(myStack);
        Thread1_2 my2 = new Thread1_2(myStack);
        Thread1_3 my3= new Thread1_3(myStack);
        Thread1_4 my4 = new Thread1_4(myStack);
        my1.setName("生产者 ");
        my2.setName("1 号消费者 ");
        my3.setName("2 号消费者 ");
        my4.setName("3 号消费者 ");
        my1.start();
        my2.start();
        my3.start();
        my4.start();


    }

}

 

1 号消费者  waiting
2 号消费者  waiting
生产者  runnable
push  size() 1
生产者  waiting
1 号消费者  runnable
pop  size() 0
1 号消费者  waiting
2 号消费者  runnable
3 号消费者  waiting
Exception in thread "2 号消费者 " java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
    at java.util.ArrayList.rangeCheck(ArrayList.java:653)
    at java.util.ArrayList.remove(ArrayList.java:492)
    at com.it.po.thread10.MyStack.pop(MyStack.java:30)
    at com.it.po.thread10.Thread1_3.run(Thread1_3.java:11)

 

 

 

 

 解决办法

package com.it.po.thread10;
import java.util.ArrayList;
import java.util.List;
public class MyStack {
private List list =new ArrayList();
synchronized  public void push(){
    try {
        while (list.size()==1) {
            System.out.println(Thread.currentThread().getName() +" waiting");
            this.wait();
        }
        System.out.println(Thread.currentThread().getName() +" runnable");
        list.add(System.nanoTime());
        this.notify();
        System.out.println("push  size() "+list.size());
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

    synchronized public void pop(){//取出
    try {
        while (list.size()==0) {
            System.out.println(Thread.currentThread().getName() +" waiting");
            this.wait();
        }
        System.out.println(Thread.currentThread().getName() +" runnable");
        list.remove(0);
        this.notify();
        System.out.println("pop  size() "+list.size());
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

}

 

if都改成while

生产者  runnable
push  size() 1
生产者  waiting
3 号消费者  runnable
pop  size() 0
3 号消费者  waiting
2 号消费者  waiting
1 号消费者  waiting

 

程序呈假死状态。

最终解决办法 :  notify 改成notifyAll

package com.it.po.thread10;
import java.util.ArrayList;
import java.util.List;
public class MyStack {
private List list =new ArrayList();
synchronized  public void push(){
    try {
        while (list.size()==1) {
            System.out.println(Thread.currentThread().getName() +" waiting");
            this.wait();
        }
        System.out.println(Thread.currentThread().getName() +" runnable");
        list.add(System.nanoTime());
        this.notifyAll();
        System.out.println("push  size() "+list.size());
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

    synchronized public void pop(){//取出
    try {
        while (list.size()==0) {
            System.out.println(Thread.currentThread().getName() +" waiting");
            this.wait();
        }
        System.out.println(Thread.currentThread().getName() +" runnable");
        list.remove(0);
        this.notifyAll();
        System.out.println("pop  size() "+list.size());
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

}

 

 

 一直执行。。。。

 

 总结:

同理:多生产和一消费,多生产和多消费参考上面即可。

 

 

 

 

 

 

posted on 2019-11-25 22:34  源无极  阅读(116)  评论(0)    收藏  举报