Java同步问题再升级
消费者与生成者
问题引出
- 多线程 生产者 消费者操作
生产者负责信息内容的 - 每当 生产者 生产完成一项完整的信息之后消费者从生成者取走信息
- 如果生产者没有 生成完成 消费者等待生成完成 如果消费者没对数据消费 生成者要等待消费后 生成
上代码
class product implements Runnable {
private Msg msg;
public product(Msg msg) {
this.msg = msg;
}
@Override
public void run() {
for (int x = 0; x < 100; x++) {
if (x % 2 == 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.msg.setTitle("laowang");
this.msg.setContent("帅哥");
} else {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.msg.setTitle("laoliu");
this.msg.setContent("不是");
}
}
}
}
class consumer implements Runnable {
private Msg msg;
public consumer(Msg msg) {
this.msg = msg;
}
@Override
public void run() {
for (int x = 0; x < 100; x++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.msg.getTitle() + ":" + this.msg.getContent());
}
}
}
class Msg {
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 tests {
public static void main(String args[]) {
Msg msg = new Msg();
new Thread(new product(msg)).start();
new Thread(new consumer(msg)).start();
}
}
结果:
laowang:帅哥
laoliu:不是
laoliu:不是
laoliu:不是
laowang:帅哥
laoliu:帅哥
laowang:帅哥
laowang:帅哥
laowang:帅哥
laowang:不是
发现数据 不同步了
有重复生成 有重复取出的问题
要想解决这个问题 最先解决的得是数据同步
最简单的步骤就是使用synchronized 关键字
把msg的get 与 set 使用synchronized 关键字来构造
上代码
class product implements Runnable {
private Msg msg;
public product(Msg msg) {
this.msg = msg;
}
@Override
public void run() {
for (int x = 0; x < 100; x++) {
if (x % 2 == 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.msg.set("laowang","帅哥");
} else {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.msg.set("laoliu","不是帅哥");
}
}
}
}
class consumer implements Runnable {
private Msg msg;
public consumer(Msg msg) {
this.msg = msg;
}
@Override
public void run() {
for (int x = 0; x < 100; x++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.msg.get());
}
}
}
class Msg {
private String title;
private String content;
public synchronized void set(String title,String content) {
this.title = title;
this.content = content;
}
public synchronized String get() {
return this.title + " - " + this.content;
}
}
class tests {
public static void main(String args[]) {
Msg msg = new Msg();
new Thread(new product(msg)).start();
new Thread(new consumer(msg)).start();
}
}
结果
laowang - 帅哥
laoliu - 不是帅哥
laowang - 帅哥
laoliu - 不是帅哥
laowang - 帅哥
laoliu - 不是帅哥
laowang - 帅哥
laoliu - 不是帅哥
laowang - 帅哥
laoliu - 不是帅哥
laowang - 帅哥
laoliu - 不是帅哥
laowang - 帅哥
换一种实现?
等待与唤醒操作
在Object类有三种方法
等待
方法 | 备注 |
---|---|
wait() | 死等 |
wait(long timeout) | 设置等待时间 |
wait(long timeout, int nanos) | 设置等待时间 |
唤醒
方法 | 备注 |
---|---|
notify() | 唤醒第一个等待的 |
notifyAll() | 唤醒所有等待的 |
package com.xiaowang;
//多线程 生产者 消费者操作
//生产者负责信息内容的
//每当 生产者 生产完成一项完整的信息之后消费者从生成者取走信息
//如果生产者没有 生成完成 消费者等待生成完成 如果消费者没对数据消费 生成者要等待消费后 生成
class product implements Runnable {
private Msg msg;
public product(Msg msg) {
this.msg = msg;
}
@Override
public void run() {
for (int x = 0; x < 100; x++) {
if (x % 2 == 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.msg.set("laowang", "帅哥");
} else {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.msg.set("laoliu", "不是帅哥");
}
}
}
}
class consumer implements Runnable {
private Msg msg;
public consumer(Msg msg) {
this.msg = msg;
}
@Override
public void run() {
for (int x = 0; x < 100; x++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.msg.get());
}
}
}
class Msg {
private String title;
private String content;
private boolean flag = true;//表示生成或者消费
//flag = ture 允许生成
//flag = false 运行消费
public synchronized void set(String title, String content) {
if (this.flag == false)
try {
super.wait();
} catch (Exception e) {
e.printStackTrace();
}
this.title = title;
try {
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
this.content = content;
this.flag = false;
super.notify();
}
public synchronized String get() {
if (this.flag == true) {//生成 还要等待
try {
super.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
try {
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
try {
return this.title + " - " + this.content;
} finally {
this.flag = true;
super.notify();
}
}
}
class tests {
public static void main(String args[]) {
Msg msg = new Msg();
new Thread(new product(msg)).start();
new Thread(new consumer(msg)).start();
}
}
结果
laoliu - 不是帅哥
laowang - 帅哥
laoliu - 不是帅哥
laowang - 帅哥
laoliu - 不是帅哥
laowang - 帅哥
laoliu - 不是帅哥
laowang - 帅哥
laoliu - 不是帅哥
laowang - 帅哥
laoliu - 不是帅哥
laowang - 帅哥
laoliu - 不是帅哥
laowang - 帅哥
这么做呢 就是增加了一条判断 判断当前的状态
如果是生成线程 那么执行 生产线程 消费线程 等待 执行完唤醒次线程
如果是消费线程 那么执行消费线程 生成线程 等待 执行完唤醒次线程