线程交互现象
小明对自家的狗子有个规定,就是在狗狗还没吃完的时候,可以继续给他加饭
不好的解决方式
狗狗感觉一千年没吃饭了,狼吞虎咽起来,最后饭只剩下最后一点点,吃饭线程中使用while循环判断是否是1,如果是1那么就一直循环,知道加饭又重新回到了起点,这虽然是狗狗能够吃的更多,那么狗狗也会长得太胖了,太胖对狗狗健康有威胁,所以是一个不好的解决方式。
package multiThread2;
public class test {
public static void main(String[] args) {
Animal a = new Animal("大黄", 3, 10);
Thread t1 = new Thread(){
@Override
public void run() {
while (true){
while (a.getFood()==1){
continue;
}
a.eatFood();
System.out.println(a.getName()+"吃饭,剩余"+a.getFood());
try {
Thread.sleep(1);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
};
t1.start();
Thread t2 = new Thread(){
@Override
public void run() {
while (true){
a.addFood();
System.out.println(a.getName()+"加饭,剩余"+a.getFood());
try {
Thread.sleep(100);//这里注意,时间必须比上面多,不然无法看见饭剩下1
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
};
t2.start();
}
}
package multiThread2;
public class Animal{
private String name;
private int year;
Animal(){}
private int food;
public Animal(String name,int year,int food){
this.name = name;
this.year = year;
this.food = food;
}
@Override
public String toString() {
return "姓名:"+ name + ",年龄:" + year + ",来干饭了,还剩"+ food + "个食物";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getFood() {
return food;
}
public void setFood(int food) {
this.food = food;
}
public synchronized void eatFood(){
synchronized(this) {
this.food--;
}
}
public void addFood(){
synchronized (this) {
this.food++;
}
}
}
使用wait和notify进行线程交互
在Animal类中,eatfood方法,当food==1时,执行this.wait()
this.wait()指的是暂停执行,释放占有
进入eatfood方法,使用this.wait()可以让吃食物线程临时释放对this的占有,这样就有机会进入addfood方法了
addfood:增加食物之后,执行this.notify
this.notify表示通知等待this的线程,可以苏醒过来了。等待在this的线程,是吃饭过程。一旦addfood()结束,加食物线程释放了this,吃食物线程,重新占有this,执行后面的吃食物工作。
package multiThread2;
public class Animal{
private String name;
private int year;
Animal(){}
private int food;
public Animal(String name,int year,int food){
this.name = name;
this.year = year;
this.food = food;
}
@Override
public String toString() {
return "姓名:"+ name + ",年龄:" + year + ",来干饭了,还剩"+ food + "个食物";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getFood() {
return food;
}
public void setFood(int food) {
this.food = food;
}
public synchronized void eatFood(){
if(food==1) {
try{
this.wait();
}catch (InterruptedException e){
e.printStackTrace();
}
this.food--;
}
}
public synchronized void addFood(){
this.food++;
this.notify();
}
}
package multiThread2;
public class test {
public static void main(String[] args) {
Animal a = new Animal("大黄", 3, 10);
Thread t1 = new Thread(){
@Override
public void run() {
while (true){
// while (a.getFood()==1){
// continue;
// }
a.eatFood();
System.out.println(a.getName()+"吃饭,剩余"+a.getFood());
try {
Thread.sleep(1);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
};
t1.start();
Thread t2 = new Thread(){
@Override
public void run() {
while (true){
a.addFood();
System.out.println(a.getName()+"加饭,剩余"+a.getFood());
try {
Thread.sleep(100);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
};
t2.start();
}
}
这里需要强调的是,wait方法和notify方法,并不是Thread线程上的方法,它们是Object上的方法。
因为所有的Object都可以被用来作为同步对象,所以准确的讲,wait和notify是同步对象上的方法。
wait()的意思是: 让占用了这个同步对象的线程,临时释放当前的占用,并且等待。 所以调用wait是有前提条件的,一定是在synchronized块里,否则就会出错。
notify() 的意思是,通知一个等待在这个同步对象上的线程,你可以苏醒过来了,有机会重新占用当前对象了。
notifyAll() 的意思是,通知所有的等待在这个同步对象上的线程,你们可以苏醒过来了,有机会重新占用当前对象了。