生成一个打印偶数和奇数的两个数字的序列?

时间:2013-08-27 16:17:32

标签: java multithreading

有两个线程一个打印{1,3,5,7,9}。另一个打印{2,4,6,8,10}

我想打印{1,2,3,4,5,6,7 ...}

package com.oddnumber.threading;

public class NumberPrint implements Runnable {
  int number=1;
  private Object lock = new Object();
  private volatile boolean isOdd = false;

  public void generateEvenNumbers(int number) throws InterruptedException {
    synchronized (lock) {
      while (isOdd == false) {
        lock.wait();
      }
      System.out.println("even" + number);
      isOdd = false;
      lock.notifyAll();
    }
  }

  public void generateOddNumbers(int number) throws InterruptedException {
    synchronized (lock) {
      while (isOdd == true) {
        lock.wait();
      }
      System.out.println("odd" + number);
      isOdd = true;
      lock.notifyAll();
    }
  }

  @Override
  public void run() {
    while(true) {
      if(number%2 == 0) {
        try {
          generateEvenNumbers(number);
          number++;
          Thread.sleep(1112);
        } catch (InterruptedException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      } else {
        try {
          generateOddNumbers(number);
          number++;
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    }
  }     
}

我用以下方法执行了它:

package com.oddnumber.threading;
public class Test
{
  public static void main(String[] args) {
    NumberPrint n1 = new NumberPrint();
    NumberPrint n2 = new NumberPrint();
    new Thread(n1).start();
    new Thread(n2).start();
  }
}

输出:

 1
 1
 2
 2
 3
 3
 4
 4
 5
 5
 6
 6
 7
 8
 7
 8
 9
 9
 10

每个数字都打印两次,但为什么两个线程之间不共享数字变量?

4 个答案:

答案 0 :(得分:4)

NumberPrint类的每个实例都有自己的lock对象实例。在两个不同的实例上使用synchronized将不起作用。方法必须使用相同的对象。一种方法是使用main()方法创建一个对象的实例并将其传递给NumberPrint构造函数,这样只有一个实例可以使用所有方法进行同步。

答案 1 :(得分:0)

首先,您需要在NumberPrint static(可能还有static volatile)中创建变量,以便在两个线程之间共享它们。这应该针对numberlockisOdd进行。如果这就是你所做的一切,你的输出将是{1,2,1,4,5,6,7,8 ......},因为两个线程都尽可能快地读取number他们开始运行,没有任何同步。最好的解决方案似乎是确保generateEvenNumbersgenerateOddNumbers在同步后读取共享的number - 这意味着删除number参数到这些例程,以及然后,当他们阅读number时,它将是共享的。

答案 2 :(得分:0)

正如NormR所说,两个线程必须共享相同的锁,例如:

public class Main {

    public static void main(String[] args) throws InterruptedException {
        Object lock = new Object();

        Thread evenThread = new Thread(new GeneratorHandler(lock, new EvenGenerator()));
        Thread oddThread = new Thread(new GeneratorHandler(lock, new OddGenerator()));

        oddThread.start();
        Thread.sleep(500);
        evenThread.start();

    }

}

public interface Generator {
    public int generate();
}

public class EvenGenerator implements Generator {
    int n = 0;

    @Override
    public int generate() {
        return n += 2;
    }
}

public class OddGenerator implements Generator {
    int n = -1;

    @Override
    public int generate() {
        return n += 2;
    }
}

public class GeneratorHandler implements Runnable {

    private Object lock;
    private Generator generator;

    public GeneratorHandler(Object lock, Generator generator) {
        this.lock = lock;
        this.generator = generator;
    }

    @Override
    public void run() {
        while (true) {

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            synchronized(lock){
                System.out.println(generator.generate());
            }


        }
    }

}

答案 3 :(得分:0)

    public class PrintOnetoTen {

    public static void main(String[] args) {

            SharedPrinter sp = new SharedPrinter();

            ExecutorService executor = Executors.newFixedThreadPool(2);
            executor.submit(new EvenNumberProducer(sp, 10));
            executor.submit(new OddNumberProducer(sp , 10));
            executor.shutdown();
        }

    }


    class SharedPrinter {

        Semaphore semEven = new Semaphore(0);
        Semaphore semOdd = new Semaphore(1);

        public void printEvenNumber(int num) {
            try {
                semEven.acquire();
            }catch(InterruptedException exception) {

            }
            System.out.println("Thread 2 - Number : " +num);
            semOdd.release();
        }

        public void printOddNumber(int num) {
            try {
                semOdd.acquire();
            }catch(InterruptedException exception) {

            }
            System.out.println("Thread 1 - Number : " +num);
                semEven.release();
        }

    }

    class EvenNumberProducer implements Runnable {

        SharedPrinter sp;
        int index;

        EvenNumberProducer(SharedPrinter sp , int index) {
            this.sp = sp;
            this.index = index;
        }

        @Override
        public void run() {
            for(int i = 2 ; i <= index ; i = i + 2 ) {
                sp.printEvenNumber(i);
            }
        }
    }

    class OddNumberProducer implements Runnable{
        SharedPrinter sp;
        int index;

        OddNumberProducer(SharedPrinter sp , int index) {
            this.sp = sp;
            this.index = index;
        }

        @Override
        public void run() {
            for(int i = 1 ; i <= index ; i = i + 2) {
                sp.printOddNumber(i);
            }
        }
    }

程序输出为:

    Thread 1 - Number : 1

    Thread 2 - Number : 2

    Thread 1 - Number : 3

    Thread 2 - Number : 4

    Thread 1 - Number : 5

    Thread 2 - Number : 6

    Thread 1 - Number : 7

    Thread 2 - Number : 8

    Thread 1 - Number : 9

    Thread 2 - Number : 10