此程序是用多线程,一个线程控制输入,一个线程控制打印。输入一次,打印一次。
小弟的问题是,为什么我已经加了标志位,并且使用了等待(输入的时候,不允许打印,以防数据出错),但是为什么还是会输入一小会,打印一小会,而不是输入一次打印一次。import java.util.concurrent.locks.*;
class Demo
{
private String name;
private String sex;
private boolean flag=false;
Lock lock=new ReentrantLock();
Condition condition_in=lock.newCondition();
Condition condition_out=lock.newCondition();
public void setMas(String name,String sex)
{
lock.lock();
if(flag)
{
try
{
condition_in.await();
}
catch (InterruptedException e)
{
e.getStackTrace();
}
}
else
{
this.name=name;
this.sex=sex;
flag=true;
condition_out.signal();
}
lock.unlock();
}
public void out()
{
lock.lock();
if (!flag)
{
try
{
condition_out.await();
}
catch (InterruptedException e)
{
e.getStackTrace();
}
}
else
{
System.out.println(this.name+"===="+this.sex);
flag=false;
condition_in.signal();
}
lock.unlock();
}
}
class InputDemo implements Runnable
{
private Demo d;
InputDemo(Demo d)
{
this.d=d;
}
public void run()
{
int num=0;
while (true)
{
if (num==0)
{
d.setMas("MIKE","MAN");
}
else
{
d.setMas("丽丽丽丽","女女女女女女");
}
num=(num+1)%2;
}
}
}
class OutputDemo implements Runnable
{
private Demo d;
OutputDemo(Demo d)
{
this.d=d;
}
public void run()
{
while (true)
{
d.out();
}
}
}
class LockDemo
{
public static void main(String[] args)
{
Demo d=new Demo();
InputDemo id=new InputDemo(d);
OutputDemo od=new OutputDemo(d);
Thread t1=new Thread(id);
Thread t2=new Thread(od);
t1.start();
t2.start(); }
}

解决方案 »

  1.   

    如果各位大神觉得这个代码太乱 http://blog.csdn.net/xuxiaocheng1/article/details/7495867
    我这里有个不乱的,话说这个插入源代码怎么用的怎么每次用了都没用的?
      

  2.   

    其实就是个典型的生产消费模式,给你个例子吧,你研究研究就明白了。package com.thread;
    public class Test { public static void main(String[] args) {
    Share s = new Share();
    Producer p = new Producer(s, 1);
    Consumer c = new Consumer(s, 1);
    p.start();
    c.start();
    }
    }
    class Share {
    private int contents;
    private boolean available = false; public synchronized int get() {
    while (available == false) {
    try {
    wait();
    } catch (InterruptedException e) {
    }
    }
    available = false;
    notifyAll();
    return contents;
    }
    public synchronized void put(int value) {
    while (available == true) {
    try {
    wait();
    } catch (InterruptedException e) {
    }
    }
    available = true;
    notifyAll();
    contents = value;
    }
    }
    class Producer extends Thread {
    private Share shared;
    private int number; public Producer(Share s, int number) {
    shared = s;
    this.number = number;
    }
    public void run() {
    for (int i = 0; i < 10; i++) {
    shared.put(i);
    System.out.println("生产者" + this.number + " 输出的数据为:" + i);
    try {
    sleep((int) (Math.random() * 100));
    } catch (InterruptedException e) {
    }
    }
    }
    }
    class Consumer extends Thread {
    private Share shared;
    private int number; public Consumer(Share s, int number) {
    shared = s;
    this.number = number;
    } public void run() {
    int value = 0;
    for (int i = 0; i < 10; i++) {
    value = shared.get();
    System.out.println("消费者" + this.number + " 得到的数据为:" + value);
    }
    }
    }
      

  3.   

    关键的问题在于唤醒后从哪开始执行,线程从等待状态返回的时候,正是满足了可以输入或者打印的时候. 那么你应该让线程执行打印或输入操作. 而你的程序是从setMas 或out 退出了。所以应该在await()醒来的时候,程序不要退出,而是把输入或打印执行完。在setMas()try/catch块后加上下面的饿语句:
    this.name=name;
    this.sex=sex;
    flag=true;
    condition_out.signal();其实上面的代码就是else后面的执行代码。这段代码有两种情况会执行:
    1 flag=false.  直接执行。
    2 flag=true 进入等待状态,而从等待退出的时候,name sex 的值都输入好了,flag=true,这时程序应该执行输入操作。同理 要在out()方法的try/catch后加上:
    System.out.println(this.name+"===="+this.sex);
    flag=false;
    condition_in.signal();原理同setMas()一样。
    楼主试试看。
      

  4.   

    这是线程假醒现象,造成数据丢失而引起的
    把if改成while就可以了
    public void setMas(String name,String sex)
    {
        lock.lock();
        //if(flag)
        while(flag)
        {
            try
            {
                condition_in.await();
            }
                catch (InterruptedException e)
            {
                e.getStackTrace();
            }
        }
        //else
        //{
            this.name=name;
            this.sex=sex;
            flag=true;
            condition_out.signal();
        //}
        lock.unlock();
    }
    public void out()
    {
        lock.lock();
        //if (!flag)
        while (! flag)
        {
            try
            {
                condition_out.await();
            }
            catch (InterruptedException e)
            {
                e.getStackTrace();
            }
        }
        //else
        //{
            System.out.println(this.name+"===="+this.sex);
            flag=false;
            condition_in.signal();
        //}
        lock.unlock();
    }分析一下一种执行的可能情况LZ就清楚了
    假设一开始out线程先执行,然后flag是false,out程进入休眠
    然后in线程执行,设置name为mike,sex为man,然后in线程唤醒out线程,此时接下来的执行分2种情况
    1 out线程先执行,因为out线程在if块里面,醒来了也不会打印信息,所以out丢失了一次打印信息
    2 in线程先执行,因为flag是true,所以in线程等待,in即将设置的参数是name为丽,sex为女,然后out线程执行,发生和1一样的情况,丢失一次打印信息在1的情况下,接下来又分2种可能的执行情况
    1-1 out线程先执行,因为flag是ture,所以out打印mike,man,flag为false
    1-2 in线程先执行,因为flag是ture,所以in线程等待,in即将设置的参数是name为丽,sex为女在2的情况,因为in线程休眠,所以只有1种执行情况
    2-1 out线程执行,打印mike,man,flag为false,唤醒in线程,因为in在if块里面,所以就算醒了也不会设置信息,所以name为丽,sex为女的信息丢失在2-1的情况下,接下来又分2种可能的执行情况
    2-1-1 out线程先执行,因为flag是false,所以out线程休眠
    2-1-2 in线程先执行,此时in线程设置的参数变为了name为mike,sex为man所以,从2-,2-1,2-1-2的情况来看,就可以知道,name为丽,sex为女的信息丢失,那么out就有可能连着2次输出的都是mike和man,当然线程的随机性还会造成更多的可能,因为线程的假醒,信息设置和打印的丢失,造成无法达到in和out正常交替,所以LZ在写多线程程序的时候,要多注意这一点。