一、前言
在多线程开发过程中最为著名的案例就是生产者和消费者操作,该操作的主要流程是
1.生产者负责信息内容的生产;
2.每当生产者完成信息的生产之后,消费者要从这里面取走信息。
3.如果生产者没有生产完成,消费者必须等待。
4.同理:如果消费者对信息没有消费完毕,生产者必须等待。
二、程序的基本实现
可以将生产者和消费者定义为2个独立的线程类对象。
1.数据一:title=chenzhou ,content=666
2.数据二:title=cz ,content=777
既然生产者(Producer)和消费者(Consumer)是两个独立的线程,所以我们需要一个message类来实现数据的保存。
三、解决数据同步
最简单的方法就是:同步代码块和同步方法
范例:解决同步操作
public class ProducerAndCustomer {
public static void main(String[] args) {
Message message = new Message();
new Thread(new Producer(message)).start();
new Thread(new Customer(message)).start();
}
}
/*生产者*/
class Producer implements Runnable{
public Message message;
public Producer(Message message){
this.message = message;
}
public void run(){
for(int i = 0; i< 100 ;i++){
if(i%2 == 0){
this.message.set("chenzhou","666");
}else{
this.message.set("cz","777");
}
}
}
}
/*消费者*/
class Customer implements Runnable{
public Message message;
public Customer(Message message){
this.message = message;
}
public void run(){
for(int i = 0; i< 100; i++){
System.out.println(this.message.get());
}
}
}
/*保存数据类,保存有主题和内容**/
class Message{
public String title;
public String content;
public synchronized void set(String title,String content){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.title = title;
this.content = content;
}
public synchronized String get(){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
return this.title+" -- "+this.content;
}
}
我们发现数据可以保持一致,但是重复操作依然存在。
四、等待与唤醒机制
对于等待与唤醒机制,主要依靠于Object提供的方法来处理的。
等待机制:
死等:public final void wait() throws InterruptedException;
设置等待时间:public final void wait(long timeout) throws InterruptedException;
设置等待时间:public final void wait(long timeout,int nanos) throws InterruptedException
唤醒机制:
唤醒第一个进程:public final void notify();
唤醒所有等待的进程:public final void notifyAll();
范例:修改message类
/**
* Created by chenzhou on 2018/9/13
*/
public class ProducerAndCustomer {
public static void main(String[] args) {
Message message = new Message();
new Thread(new Producer(message)).start();
new Thread(new Customer(message)).start();
}
}
/*生产者*/
class Producer implements Runnable{
public Message message;
public Producer(Message message){
this.message = message;
}
public void run(){
for(int i = 0; i< 100 ;i++){
if(i%2 == 0){
this.message.set("chenzhou","666");
}else{
this.message.set("cz","777");
}
}
}
}
/*消费者*/
class Customer implements Runnable{
public Message message;
public Customer(Message message){
this.message = message;
}
public void run(){
for(int i = 0; i< 100; i++){
System.out.println(this.message.get());
}
}
}
/*保存数据类,保存有主题和内容**/
class Message{
private String title;
private String content;
/*flag=true 表示允许生产,不允许消费
* flag=false 表示允许消费,不允许生产
* */
private Boolean flag =true;
public synchronized void set(String title,String content){
if(this.flag == false){
try {
super.wait();//等待消费
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.title = title;
this.content = content;
this.flag = false;
super.notify();//唤醒消费进程
}
public synchronized String get(){
if(this.flag == true){
try {
super.wait();//等待生产
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
return this.title + " -- " + this.content;
}finally {
this.flag=true;
super.notify();//唤醒生产进程
}
}
}
这是最原始的处理方案,整个的等待,同步,唤醒机制都由开发者自行通过原生代码实现控制。