一、生产者与消费者模式
生产者将生产出来的信息不断存入一个区域内,消费者将信息从该区域内不断读取出来;
生产者录入信息
消费者读取信息
生产者与消费者模式是一种经典同步案例, 它描述是有一块缓冲区作为仓库,生产者可以将产品放入仓库,消费者则可以从仓库中取走产品。解决生产者/消费者问题的方法可分为两类:(1)采用某种机制保护生产者和消费者之间的同步;(2)在生产者和消费者之间建立一个管道。第一种方式有较高的效率,并且易于实现,代码的可控制性较好,属于常用的模式。第二种管道缓冲区不易控制,被传输数据对象不易于封装等,实用性不强。
1、wait() / notify()方法
wait() / nofity()方法是基类Object的两个方法,也就意味着所有Java类都会拥有这两个方法,这样,我们就可以为任何对象实现同步机制。
wait()方法:当缓冲区已满/空时,生产者/消费者线程停止自己的执行,放弃锁,使自己处于等等状态,让其他线程执行。
notify()方法:当生产者/消费者向缓冲区放入/取出一个产品时,向其他等待的线程发出可执行的通知,同时放弃锁,使自己处于等待状态。
2.线程同步
synchronized关键字,是一种同步锁。它修饰的对象有以下几种:
1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
2. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
3. 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
4. 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象;
3.实现步骤
1.第一步,首先让两个线程实现资源共享
2.第二步,解决线程并发问题
3.解决生产者和消费者依次进行的问题
volatile 修饰的属性为线程可见性属性
同步代码块synchronized()最好放在while里面,不然当一个线程一次获得了属性,就会将while循环执行完毕,所以同步代码块synchronized最好就只包括一次运行就结束的代码
实例代码:循环录入读取电影票
public class Movie {
private String name ;
private String info;
private boolean flag=true;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
public synchronized void set(String name , String info){
if (!flag) {
try {
super.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.name=name;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.info=info;
flag=false;
super.notify();
}
public synchronized void get(){
if (flag) {
try {
super.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("名字:"+this.getName()+" —— "+this.getInfo());
flag=true;
super.notify();
}
}
public class Productor implements Runnable{
private Movie movie=null;
boolean flag=false;
public Productor(Movie movie) {
super();
this.movie = movie;
}
public void run() {
for (int i = 0; i < 50; i++) {
if (flag) {
this.movie.set("变形金刚","一部科幻电影");
flag=false;
}else{
this.movie.set("神偷奶爸", "一部3d动画电影");
flag=true;
}
}
}
}
public class Consumer implements Runnable{
private Movie movie=null;
public Consumer(Movie movie) {
super();
this.movie = movie;
}
public void run() {
for (int i = 0; i < 50 ; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.movie.get();
}
}
}
public class Test {
public static void main(String[] args) {
Movie movie=new Movie();
Thread productor=new Thread(new Productor(movie));
Thread consumer=new Thread(new Consumer(movie));
productor.start();
consumer.start();
}
}