读书人

不知道为何同步代码出现错误。求高手帮

发布时间: 2012-12-28 10:29:05 作者: rapoo

不知道为何同步代码出现异常。求高手帮助,跪谢了!
本帖最后由 xingqi10 于 2012-11-20 11:53:51 编辑 请求各位高手帮助,小弟正在学习线程通信的生产者和消费者这节课程,但是遇到一个问题,就是下面的代码运行出现异常,我想让它运行正常,正常情况下是:

有一个数据存储空间,划分为两部分,一部分用于存储人的姓名,另一部分用于存储人的性别;

包含两个线程,一个线程不停向数据存储空间添加数据(生产者),另一个线程从数据空间取出数据(消费者);

因为线程的不确定性,存在于以下两种情况:
1、若生产者线程刚向存储空间添加了人的姓名还没添加人的性别,CPU就切换到了消费者线程,消费者线程把姓名和上一个人的性别联系到一起;
2、生产者放了若干数据,消费者才开始取数据,或者是消费者取完一个数据,还没等到生产者放入新的数据,又重复的取出已取过的数据;

Person -- name---sex 春哥 --- 男 著姐 --- 女

1.数据的设置错误(使用synchronized解决);
2.出现了重复取或重复设置的问题 ;(使用wait和notify解决)

原因:synchronized现在在run方法里面,如果把方法写在Person类里面,run方法再调用Person类里面的方法,并且在Person类里面的方法加synchronized同步代码块和wait、notify方法。就可以运行正常。
但是现在把synchronized和wait、notify方法放到run方法里面就运行出现异常了。
下面的代码块运行起来出现异常!synchronized在run方法里面!synchronized 放在Person类里面运行就正常,放在run方法里面就出现异常,咋回事啊?


class Person {
private String name;
private String sex;
private Boolean isEmpty = Boolean.TRUE;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getSex() {
return sex;
}

public void setSex(String sex) {
this.sex = sex;
}

public Boolean getIsEmpty() {
return isEmpty;
}

public void setIsEmpty(Boolean isEmpty) {
this.isEmpty = isEmpty;
}
}

class Producer implements Runnable {

private Person p;

public Producer(Person p) {
this.p = p;
}

public void run() {
for (int i = 0; i < 100; i++) {
synchronized (p) {

if (!p.getIsEmpty().equals(Boolean.TRUE)) {
try {
p.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

if (i % 2 == 0) {
p.setName("春哥");
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
p.setSex("男");
} else {
p.setName("著姐");
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
p.setSex("女");
}
p.setIsEmpty(Boolean.FALSE);
p.notify();
}
}
}
}

class Consumer implements Runnable {
private Person p;

public Consumer(Person p) {
this.p = p;
}

public void run() {
for (int i = 0; i < 100; i++) {
synchronized (p) {
if (!p.getIsEmpty().equals(Boolean.FALSE)) {
try {
p.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
String name = p.getName();
String sex = p.getSex();
System.out.println(name + "--->" + sex);
}
p.setIsEmpty(Boolean.TRUE);
p.notify();
}
}
}

public class CopyOfProducer_ConsumerDemo {
public static void main(String[] args) {


Person p = new Person();
new Thread(new Producer(p), "生产者").start();
new Thread(new Consumer(p), "消费者").start();

}
}


下面的代码运行正常!下面的代码 synchronized 在Person类里面修饰方法。

class Person {
private String name;
private String sex;
private Boolean isEmpty = Boolean.TRUE;

public void set(String name, String sex) {
synchronized (this) {
if (!isEmpty.equals(Boolean.TRUE)) {
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.name = name;
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.sex = sex;
isEmpty = Boolean.FALSE;
this.notify();
}
}

public void get() {
synchronized (this) {
if (!isEmpty.equals(Boolean.FALSE)) {
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
String name = getName();
String sex = getSex();
System.out.println(name + "--->" + sex);
isEmpty = Boolean.TRUE;
this.notify();
}
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getSex() {
return sex;
}

public void setSex(String sex) {
this.sex = sex;
}
}

// 生产者
class Producer implements Runnable {

private Person p;

public Producer(Person p) {
this.p = p;
}

public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 == 0) {
p.set("春哥哥", "男");
} else {
p.set("著姐", "女");
}
}
}

}

class Consumer implements Runnable {
private Person p;

public Consumer(Person p) {
this.p = p;
}

public void run() {
for (int i = 0; i < 100; i++) {
p.get();
}
}
}

public class Producer_ConsumerDemo {
public static void main(String[] args) {
Person p = new Person();
new Thread(new Producer(p), "生产者").start();
new Thread(new Consumer(p), "消费者").start();

}
}

[最优解释]
把Consumer类的
p.setIsEmpty(Boolean.TRUE);
p.notify();
这两行代码放到synchronized块中:

public class Consumer implements Runnable{
private Person p;

public Consumer(Person p) {
this.p = p;
}


public void run() {
for (int i = 0; i < 100; i++) {
synchronized (p) {
if (!p.getIsEmpty().equals(Boolean.FALSE)) {
try {
p.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
String name = p.getName();
String sex = p.getSex();
System.out.println(name + "--->" + sex);
p.setIsEmpty(Boolean.TRUE);
p.notify();
}
}
}
}


[其他解释]
Consumer这个类你能编译通过?
以下两行代码没有在同步块里(synchronized (p))
p.setIsEmpty(Boolean.TRUE);
p.notify();

读书人网 >J2SE开发

热点推荐