我想实现一个两个线程对同一个变量,一个线程加,一个线程减的程序。可是打印的结果是1,2,3,4,5,6,7...而不是1,0,1,0..
想知道为什么
程序如下:
public class Core {
public static void main(String[] args) throws Exception{
Operation op = new Operation();
WorkerBear b1 = new WorkerBear(op);
EatBear b2 = new EatBear(op);
Thread t1 = new Thread(b1);
Thread t2 = new Thread(b2);
t2.start();
t1.start();
}
}public class WorkerBear implements Runnable{
private Operation op;

public WorkerBear(Operation op){
this.op = op;
}

@Override
public void run() {
// TODO Auto-generated method stub
while(true){
op.increment();
}
}
}public class EatBear implements Runnable{
private Operation op;

public EatBear(Operation op){
this.op = op;
} @Override
public void run() {
// TODO Auto-generated method stub
while(true){ //如果这里加入一个Thread.sleep()就好使,为什么呢
op.decrement();
}
}
}public class Operation {
int box = 0 ;

public synchronized void increment() {
box++;
try {
Thread.sleep(1000);
System.out.println(box);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public synchronized void decrement() {
box--;
try {
Thread.sleep(1000);
System.out.println(box);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

解决方案 »

  1.   

    汗,因为你把sleep(1000)放到同步方法里面了...
    一个线程sleep的时候,没有释放锁,所以另一个线程无法执行
    sleep完释放锁的时候,又没有做线程礼让,或唤醒其他线程的动作,系统把时间片仍然分给该线程,
    所以就一直加加加
    所以sleep(1000)要放在while循环中才行
      

  2.   

    加完1后接着睡,睡醒了接着加(因为拿着锁),所以一直加下去。
    所以必须把睡眠类放在带锁的方法的外面,睡眠是腾出足够的时间让 1, 0,1,0 出现规律些。
    所以放在生产者和消费着的while里面,而且操作类不是线程类,不应该写睡眠方法啊。生产者和消费者
    才都是线程类,你可以不睡眠看看效果,大致也能看出来。。
      

  3.   

    一楼说的正确 改改吧 我博客有类似的 可以看看http://blog.csdn.net/mengxiangyue/article/details/6871219
      

  4.   

    不要用sleep  控制程序流程   这是一个典型的生产者消费者 问题    ,看看  java  中如何实现  同步  synchronized   wait  notify notifyAll 怎么用你就懂了
      

  5.   

    我想知道,比如A线程调用sleep后,B线程是在等待A释放锁吧。但是这个时候需要调用nofify才能让B线程工作吗
      

  6.   

    那为什么我把sleep放在外面的时候B线程就能获得到锁呢,我也是没有唤醒B线程呀
      

  7.   

    没有调用wait,就不需要用notify唤醒
    每个线程离开synchronized处理块就会释放锁,因为没有调用wait,所以系统会自动给线程分配CPU,哪个线程获得CPU权限,哪个线程就执行
      

  8.   

    是呀,那即使是thread1的increment()方法里面有一个sleep(),当increment()退出的时候,thread2的decrement()不同样是有可能获得cpu吗?为什么事实上只有thread1总是获得cpu呢?这点我不太懂
      

  9.   

    线程是系统随机分配CPU执行的,所以这种情况也只是一个巧合
    造成这种巧合,可能是thread1刚sleep结束获得CPU继续执行的时候(比如系统分给thread1 0.5微妙CPU时间),因为打印语句很快就结束了,所以synchronized块结束以后(可能打印只需要0.3微妙),thread1的CPU分配时间还没有到(还剩0.2微妙),这样thread1继续wahile循环,又进入synchronized块了,所以thread2获得CPU时间的时候,因为thread1占用着锁,所以thread2还是不能执行像这种随机的结果,你多跑几次,时间再长一点,估计就能看到不同的结果了
      

  10.   

    这里有个参考例子,希望对你有帮助:/**
     * 
     */
    package cn.luochengor.csdn;import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.TimeUnit;/**
     * 实现两个线程对同一个变量,一个线程加,一个线程减的程序 打印的结果是:1,0,1,0..
     * 
     * @Author luochengor
     * @Date Oct 25, 2011
     * @Email [email protected]
     */
    public class OneZero {
    private int number = 0;
    private boolean isOne = false; public synchronized int toOne() {
    number++;
    isOne = true;
    notifyAll();
    return number;
    } public synchronized int toZero() {
    number--;
    isOne = false;
    notifyAll();
    return number;
    } public synchronized void waitToOne() throws InterruptedException {
    while (!isOne) {
    wait();
    }
    } public synchronized void waitToZero() throws InterruptedException {
    while (isOne) {
    wait();
    }
    } /**
     * @param args
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {
    OneZero oz = new OneZero();
    ExecutorService exec = Executors.newCachedThreadPool();
    exec.execute(new ToOne(oz));
    TimeUnit.MILLISECONDS.sleep(50);
    exec.execute(new ToZero(oz));
    TimeUnit.SECONDS.sleep(5);
    exec.shutdownNow();
    }}class ToOne implements Runnable {
    private OneZero oz; public ToOne(OneZero oz) {
    this.oz = oz;
    } public void run() {
    try {
    while (!Thread.interrupted()) {
    TimeUnit.MILLISECONDS.sleep(600);
    System.out.println(oz.toOne());
    oz.waitToZero();
    }
    } catch (InterruptedException e) {
    System.out.println("InterruptedException class ToOne");
    }
    }
    }class ToZero implements Runnable {
    private OneZero oz; public ToZero(OneZero oz) {
    this.oz = oz;
    } public void run() {
    try {
    while (!Thread.interrupted()) {
    TimeUnit.MILLISECONDS.sleep(600);
    System.out.println(oz.toZero());
    oz.waitToOne();
    }
    } catch (InterruptedException e) {
    System.out.println("InterruptedException class ToZero");
    }
    }
    }运行结果:1
    0
    1
    0
    1
    0
    1
    0
    1
    InterruptedException class ToZero
    InterruptedException class ToOne仅供参考,如有错误还望大家指教
      

  11.   

    楼主先去了解下这个类Thread.State,弄明白线程的各种状态(这是很重要的)。
    其次是要明白Java的线程调度机制是依赖操作系统的,特别要了解抢占式调度机制(学习花费不了多少时间)。再回过头来看这些问题就非常清楚了。修改你的Operation类
    示例:class Operation {
        int box = 0 ;
        boolean flag = true;
        
        public synchronized void increment() {
         if(flag == false){
    try {
    wait();
    } catch (InterruptedException e1) {
    e1.printStackTrace();
    notifyAll();
    }
         }
            box++;
            try {
                Thread.sleep(1000);
                System.out.println(box);
                flag = false;
                notifyAll();
            } catch (InterruptedException e) {
                e.printStackTrace();
                notifyAll();
            }
        }
        public synchronized void decrement() {
         if(flag == true){
         try {
    wait();
    } catch (InterruptedException e1) {
    e1.printStackTrace();
    notifyAll();
    }
         }
            box--;
            try {
                Thread.sleep(1000);
                System.out.println(box);
                flag = true;
                notifyAll();
            } catch (InterruptedException e) {
                e.printStackTrace();
                notifyAll();
            }
        }
    }