学习和理解JAVA线程同步--生产者与消费者例子

来源:互联网 发布:淘宝店铺怎么暂停营业 编辑:程序博客网 时间:2024/05/16 05:22

JAVA线程同步通常需要使用sychronized对临界资源进行加所谓的临界资源就是指这些线程共同使用的资源。

sychronized通常是放在方法名前,这是表示这个方法是同步的,实际上是对this加锁。

或者放在一个对象前,对某个共同使用的对象加锁。


生产者和消费者的例子是非常经典的,这里需要定义一个池子,用于往里放入产品。定义生产者不断生产产品,当池子不满的情况下可以继续放,满了则等待。

消费者一直从池子取,池子空则等待。

我们使用实现runnable来实现生产者和消费者。

写一个同步栈作为池子,对push和pop方法进行同步。
代码如下:

class SycnStack{private Integer index=0;private char[] data;public SycnStack(int num){data = new char[num];}public void push(char c){synchronized (this) {//对index加锁为何不行???必须thiswhile(index==data.length-1) {System.out.println("池子已经满,不能放入了!"+Thread.currentThread().toString());try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}this.notify();//获取锁data[index]=c;System.out.println("放入"+c+" "+Thread.currentThread().toString());index++;}}public Character pop(){synchronized (this) {while(index==0){System.out.println("池子已经空了,取不了了!"+Thread.currentThread().toString());try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}this.notify();index--;char c = data[index];System.out.println("取出"+c+" "+Thread.currentThread().toString());return c;}}

然后写生产者和消费者,其run方法就是不断的生产产品放入池子或取出产品:

class Producer implements Runnable{private SycnStack stack;public Producer(SycnStack stack){this.stack = stack;}@Overridepublic void run() {int i=10;while(i-->0){stack.push( (char)(26*Math.random()+'A'));Thread.yield();}}}class Consumer implements Runnable{private SycnStack stack;public Consumer(SycnStack stack){this.stack = stack;}@Overridepublic void run() {int i=10;while(i-->0){stack.pop();Thread.yield();}}}
main方法如下,创建一个栈用于放产品,然后创建生产者和消费者都用这个产品栈,并启动:

public class ProductorConsumer {public static void main(String[] args){SycnStack s = new SycnStack(5);new Thread(new Producer(s)).start();new Thread(new Consumer(s)).start();}}
结果如下:

放入G Thread[Thread-0,5,main]放入L Thread[Thread-0,5,main]放入D Thread[Thread-0,5,main]放入K Thread[Thread-0,5,main]池子已经满,不能放入了!Thread[Thread-0,5,main]取出K Thread[Thread-1,5,main]放入P Thread[Thread-0,5,main]池子已经满,不能放入了!Thread[Thread-0,5,main]取出P Thread[Thread-1,5,main]放入E Thread[Thread-0,5,main]池子已经满,不能放入了!Thread[Thread-0,5,main]取出E Thread[Thread-1,5,main]放入M Thread[Thread-0,5,main]池子已经满,不能放入了!Thread[Thread-0,5,main]取出M Thread[Thread-1,5,main]放入P Thread[Thread-0,5,main]池子已经满,不能放入了!Thread[Thread-0,5,main]取出P Thread[Thread-1,5,main]放入Q Thread[Thread-0,5,main]池子已经满,不能放入了!Thread[Thread-0,5,main]取出Q Thread[Thread-1,5,main]放入L Thread[Thread-0,5,main]取出L Thread[Thread-1,5,main]取出D Thread[Thread-1,5,main]取出L Thread[Thread-1,5,main]取出G Thread[Thread-1,5,main]


再看同步栈的代码第十行,是对this加锁,指的就是对当前这个栈加锁。

之前我测试使用对index加锁,发现是会报错的,我想可能是因为临界资源不仅是index,还有data,如果只对index加锁,当一个线程在用栈的时候,另一个线程仍然能够使用这个栈,就会造成index的混乱之后就报错了。

如果谁有更详细的解释也可以告诉我。