首页 > 代码库 > 【java】生产者——消费者 线程模型
【java】生产者——消费者 线程模型
下面的4个文件体现了多线程的知识,以及线程同步(synchronized)的使用。其PopThread类对应消费者,PushThread类对应生产者,SafeStack对应存放资源的仓库。下面的TestSafeStack创建了1个生产者对象,1个存放资源的仓库对象,2个消费者对象。
消费者类:
1 /* 2 * 通过实现Runnable接口实现线程 3 */ 4 public class PushThread implements Runnable 5 { 6 /* 7 * 创建一个SafeStack类的变量 8 */ 9 private SafeStack s;10 11 public PushThread(){}12 /*13 * 通过有参的构造函数,传入临界资源14 */15 public PushThread(SafeStack s)16 {17 this.s = s;18 }19 20 /**21 * 重写run()方法22 */23 @Override24 public void run()25 {26 int temp = 0;27 28 for(int i=0;i<100;i++)29 {30 /*31 * 产生一个[0,10)的数字,并且保存到temp变量中32 */33 java.util.Random r = new java.util.Random();34 temp = r.nextInt(10);35 //调用临界资源中push方法36 s.push(temp);37 38 /*39 * 调用Thread.sleep()方法,让当前线程休眠0.1秒后再执行40 */41 try {42 Thread.sleep(100);43 }44 catch(InterruptedException e){45 e.printStackTrace();46 }47 }48 } 49 }
消费者类:
1 public class PopThread extends Thread { 2 private SafeStack s; 3 4 public PopThread() { 5 } 6 7 public PopThread(SafeStack s) { 8 this.s = s; 9 }10 11 public void run() {12 for (int i = 0; i < 100; i++) {13 int temp = s.pop();14 System.out.println("->" + temp + "<-");15 try {16 Thread.sleep(100);17 } catch (InterruptedException e) {18 e.printStackTrace();19 }20 }21 }22 }
仓库类:
public class SafeStack{ private int top = 0;//下标 /* * 用于存储产生的随机数整数 */ private int[] values = new int[10];//数组 /* * 压栈和出栈的标志,通过dataAvailable变量控制push()方法和pop()方法中线程的等待。 * dataAvailable的值默认是false,最开始让pop()方法中线程中等待。 */ private boolean dataAvailable = false; public void push(int n)//压栈方法 { /* * 使用synchronized关键字实现同步锁 */ synchronized(this) { /* * 如果dataAvailable的值是true,则让线程线程进入等待。 */ while(dataAvailable)//循环锁 {//while是循环判断,if是单次判断 try {//必须在synchronized语句块内调用wait wait();//等待,交钥匙后进等待池 } catch(InterruptedException e) { e.printStackTrace(); } } values[top] = n; System.out.println("压入数字"+n+"步骤1完成"); top++;//入栈完成 if(top>=values.length){//当values数组满后才改变状态 dataAvailable = true;//状态变为出栈 notifyAll();//从等待池中唤醒所有线程 System.out.println("压入数字完成"); } } //同步结束 } public synchronized int pop() { while(!dataAvailable) { try { wait(); } catch(InterruptedException e) { e.printStackTrace(); } } System.out.print("弹出"); top--;//每一次取出一个数字 int test=values[top]; if(top<=0){//当数组中的所有数据都弹出完后才改变状态 dataAvailable = false; //唤醒正在等待压入数据的线程 notifyAll(); } return test; } }
测试类:
1 public class TestSafeStack{ 2 public static void main(String[] args){ 3 /* 4 * 只创建一个临界资源 5 */ 6 SafeStack s = new SafeStack(); 7 8 PushThread r1 = new PushThread(s); 9 PopThread r2 = new PopThread(s);10 PopThread r3 = new PopThread(s);11 12 /*13 * 创建三个线程,一个PushThread和两个PopThread线程14 */15 Thread t1 = new Thread(r1);16 Thread t2 = new Thread(r2); 17 Thread t3 = new Thread(r3);18 19 t1.start();20 t2.start();21 t3.start();22 } 23 }
同步需要使用关键字synchronized,语法格式为:
synchronized(对象引用){//需要被同步的代码}
如果需要同步整个run,则只需要在run方法上加上synchronized关键字即可
public synchronized void run() {...}
创建多线程也可以通过匿名内部类构造器来实现,构造器适合于创建对象的资源只使用一次。比如:
new Thread(){//继承的构造器 @Override public void run(){ for(int i=0;i<10;i++){ System.out.println("<"+i+">"); try{ Thread.sleep(1000); }catch(InterruptedException e){ e.printStackTrace(); } } } }.start(); Thread td=new Thread(new Runnable(){//实现接口的构造器 @Override public void run() { for(int j=0;j<10;j++){ System.out.println(">"+j+"<"); try{ Thread.sleep(2000); }catch(InterruptedException e){ e.printStackTrace(); } } } }); td.start();//其中线程
当时上面的例子就不可以通过构造器来实现,因为在TestSafeStack.java中的创建的临界资源s
SafeStack s = new SafeStack()
被用于创建三个对象,就是:
PushThread r1 = new PushThread(s); PopThread r2 = new PopThread(s); PopThread r3 = new PopThread(s);
所以涉及到临界资源的问题都不可以通过构造器来实现。
【java】生产者——消费者 线程模型
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。