知识点:
1. 生产者和消费者问题的产生。
2.Object类对多线程的产生。
具体内容:
问题的引出:
生产者和消费者指的是两个不同的线程类对象,操作同一资源的情况。具体的操作流程如下。
- 生产者负责生产数据,消费者负责取走数据。
- 生产者每生产完一组数据之后,消费者就去走一组数据。
现在假设要生产的数据如下:
- 第一组数据:title=雷锋,content=好学生一枚;
- 第二组数据:title=雷人的动物,content=草泥马;
package 多线程;
class Info{
private String title;
private String content;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
class Productor implements Runnable{
private Info info;
public Productor(Info info){
this.info = info;
}
@Override
public void run() {
for(int x=0;x<100;x++)
if(x%2==0){ //偶数
this.info.setTitle("雷锋!");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.info.setContent("好学生一枚!");
}else{
this.info.setTitle("雷人的动物!");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.info.setContent("草泥马!");
}
}
}
class Customer implements Runnable{
private Info info;
public Customer(Info info){
this.info=info;
}
@Override
public void run() {
for(int x=0;x<100;x++){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.info.getTitle()+"-"+this.info.getContent());
}
}
}
public class T {
public static void main(String args[]){
Info info = new Info();
new Thread(new Productor(info)).start();
new Thread(new Customer(info)).start();
}
}
运行结果:
现在实际上通过以上的代码可以发现两个严重问题:
- 数据错位,发现不再是一个所需要的完整数据;
- 数据重复取出,数据重复设置。
package 多线程;
class Info{
private String title;
private String content;
public synchronized void set(String title,String content){
this.title = title;
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.content = content;
}
public synchronized void get(){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.title+"-"+this.content);
}
}
class Productor implements Runnable{
private Info info;
public Productor(Info info){
this.info = info;
}
@Override
public void run() {
for(int x=0;x<100;x++)
if(x%2==0){ //偶数
this.info.set("王惊雷","好学生一枚");
}else{
this.info.set("可爱的动物","草泥马");
}
}
}
class Customer implements Runnable{
private Info info;
public Customer(Info info){
this.info=info;
}
@Override
public void run() {
for(int x=0;x<100;x++){
this.info.get();
}
}
}
public class T {
public static void main(String args[]){
Info info = new Info();
new Thread(new Productor(info)).start();
new Thread(new Customer(info)).start();
}
}
此时数据的错位问题得到了很好的解决,但是重复操作的问题更加严重了(大部分现实输出是:王惊雷,可爱动物出现太少)
解决重复问题:
如果想要实现整个代码的操作,必须加入等待与唤醒机制。在Object类里面专门提供有处理方法。
- 等待:public final void wait() throws InterruptedException;
- 唤醒第一个等待线程: public final void notify ();
- 唤醒全部等待线程,那个优先级高就先执行 :public final void notifyAll();
-
package 多线程; class Info{ private String title; private String content; private boolean flag = true; //flag = true:表示可以生产,但是不可以取走 //flag = false:表示可以取走,但是不可以生产 public synchronized void set(String title,String content){ //重复进入到set()方法里面,发现不能够生产,所以要等待 if(this.flag == false){ try { super.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } this.title = title; try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } this.content = content; this.flag=false; //修改生产标记 super.notify(); //唤醒其他等待线程 } public synchronized void get(){ //还没生产 if(this.flag == true){ try { super.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(this.title+"-"+this.content); this.flag=true; super.notify(); } } class Productor implements Runnable{ private Info info; public Productor(Info info){ this.info = info; } @Override public void run() { for(int x=0;x<100;x++) if(x%2==0){ //偶数 this.info.set("王惊雷","好学生一枚"); }else{ this.info.set("可爱的动物","草泥马"); } } } class Customer implements Runnable{ private Info info; public Customer(Info info){ this.info=info; } @Override public void run() { for(int x=0;x<100;x++){ this.info.get(); } } } public class T { public static void main(String args[]){ Info info = new Info(); new Thread(new Productor(info)).start(); new Thread(new Customer(info)).start(); } }
面试题:请解释sleep()和wait()的区别?
-
Sleep()是Thread类定义的方法,wait()是Object类定义的方法;
-
Sleep()可以设置休眠时间,时间一到自动唤醒,而wait()需要等待notify()进行唤醒。
总结:这是一个经典的多线程处理模型,掌握它属于一个个人能力的提升,同时可以更加理解Object类的作用。