使用线程进行奇数偶数打印

时间:2011-05-16 12:20:59

标签: java multithreading thread-safety

奇数偶数打印使用thread.Create一个线程类,两个线程实例。一个将打印奇数,另一个将打印偶数。

我做了以下编码。但它涉及死锁状态。有人可以解释一下可能是什么原因吗?

public class NumberPrinter implements Runnable{
private String type;
private static boolean oddTurn=true;


public NumberPrinter(String type){
    this.type=type;
}
public void run() {
    int i=type.equals("odd")?1:2;
    while(i<10){
        if(type.equals("odd"))
            printOdd(i);
        if(type.equals("even"))
            printEven(i);
        i=i+2;
    }

}

private synchronized void printOdd(int i){
    while(!oddTurn){
        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    System.out.println(type + i);
    oddTurn=false;
    notifyAll();
}

private synchronized  void printEven(int i){
    while(oddTurn){
        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace(); 
        }
    }
    System.out.println(type + i);
    oddTurn=true;
    notifyAll();

}

public static void main(String[] s){
    Thread odd=new Thread(new NumberPrinter("odd"));
    Thread even=new Thread(new NumberPrinter("even"));
    odd.start();
    even.start();

}
}

Out Put: odd1 even2


然后陷入僵局!!!!!!

感谢您的帮助。

13 个答案:

答案 0 :(得分:13)

您正在等待并通知不同的对象(监视器)。

我们的想法是,当您正在obj.wait()obj.notify()时,可以致电objA.wait()等待某人objB.notify()

将您的printOdd方法更改为

private void printOdd(int i) {
    synchronized (lock) {                        // <-------
        while (!oddTurn) {
            try {
                lock.wait();                     // <-------
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(type + i);
        oddTurn = false;
        lock.notifyAll();                        // <-------
    }
}

printEven方法类似。

然后为NumberPrinter提供lock对象:

Object lock = new Object();
Thread odd = new Thread(new NumberPrinter("odd", lock));
Thread even = new Thread(new NumberPrinter("even", lock));

<强>输出:

odd1
even2
odd3
even4
odd5
even6
odd7
even8
odd9

答案 1 :(得分:4)

代码中存在很多错误。

首先,synchronized语句无效。您创建两个线程实例,每个实例只调用自己的方法。 synchronized仅在另一个线程可以调用方法时才有用。

然后notifyAll()因同样的原因无效。 odd.notifyAll() even未挂到wait()

所以你需要的是另一个包含状态的对象,两个线程都可以看到和使用它。在第三个实例上使用synchronizedwait()notifyAll()

答案 2 :(得分:2)

使用Lock界面可以解决同样的问题:

NaturalOrder.java

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class NaturalOrder {

    public int currentNumber = 1;
    public boolean evenOdd = false;

    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    public static void main(String[] args) {
        NaturalOrder naturalOrder = new NaturalOrder();
        Thread t1 = new Thread(new OddNumberLock(naturalOrder, naturalOrder.lock, naturalOrder.condition));
        Thread t2 = new Thread(new EvenNumberLock(naturalOrder, naturalOrder.lock, naturalOrder.condition));
        t1.start();
        t2.start();
    }
}

OddNumberLock.java

import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

public class OddNumberLock implements Runnable {

    NaturalOrder naturalOrder;
    Lock lock;
    Condition condition;

    public OddNumberLock(NaturalOrder naturalOrder, Lock lock, Condition condition) {
        this.naturalOrder = naturalOrder;
        this.lock = lock;
        this.condition = condition;
    }

    @Override
    public void run() {
        lock.lock();
        while (naturalOrder.currentNumber < 20) {
            while (naturalOrder.evenOdd != false) {
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            try {
                Thread.sleep(ThreadLocalRandom.current().nextInt(1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (naturalOrder.currentNumber % 2 != 0) {
                System.out.println(naturalOrder.currentNumber);
            }
            naturalOrder.currentNumber++;
            naturalOrder.evenOdd = true;

            condition.signalAll();
        }
        lock.unlock();
    }
}

EvenNumberLock.java

import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

public class EvenNumberLock implements Runnable {

    NaturalOrder naturalOrder;
    Lock lock;
    Condition condition;

    public EvenNumberLock(NaturalOrder naturalOrder, Lock lock, Condition condition) {
        this.naturalOrder = naturalOrder;
        this.lock = lock;
        this.condition = condition;
    }

    @Override
    public void run() {
        lock.lock();
        while (naturalOrder.currentNumber < 20) {
            while (naturalOrder.evenOdd != true) {
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

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

            if (naturalOrder.currentNumber % 2 == 0) {
                System.out.println(naturalOrder.currentNumber);
            }
            naturalOrder.currentNumber++;
            naturalOrder.evenOdd = false;
            condition.signalAll();
        }
        lock.unlock();
    }
}

答案 3 :(得分:1)

我认为问题可能是printOddprintEven在不同的锁(Thread的对象实例锁)上同步。因此,您无法保证静态变量oddTurn的更改将在另一个线程中可见。尝试使oddTurn易变为开始。

答案 4 :(得分:1)

我这样做了

public class OddEven{
        public static void main(String[] args){
            Print o=new Print();
            Thread even=new Thread(new MyRunnable(2,o));
            Thread odd=new Thread(new MyRunnable(1,o));
            even.start();
            odd.start();
        }
}
class MyRunnable implements Runnable{
        int start;
        Print ob;
        MyRunnable(int s,Print o){
            start=s;
            ob=o;
        }
        public void run(){
            for(int i=start;i<=20;i+=2)
                ob.display(i);
        }   
}
class Print{
        int rem=0;
        synchronized void display(int n){
            while(n%2==rem)
                try{
                    wait();
                }
                catch(Exception e){System.out.println("Display interrupted");}
            System.out.print(n+" ");
            rem=n%2;
            notify();
        }           
}

答案 5 :(得分:0)

volatile变量中缺少oddTurn个关键字。没有它,就无法保证线程看到实际值。

答案 6 :(得分:0)

i使用共享对象来控制执行顺序

class Counter implements Runnable {
  int count;
  static Class cl = Counter.class;

  public synchronized void increment() {
        String tname = Thread.currentThread().getName();
        System.out.printf("%s: %d\n", tname, count++);
  }

  @Override
  public void run() {
        String tname = Thread.currentThread().getName();
        while (true) {

              increment();
              synchronized (Counter.class) {
                    try {
                          cl.notify();
                          cl.wait();
                    } catch (Exception e) {
                          e.printStackTrace();
                    }
              }

        }
  }
}

public class WaitNotify {
public static void main(String[] args) {
    Counter c = new Counter();
    Thread t1 = new Thread(c, "thread1");
    Thread t2 = new Thread(c, "thread2");
    t1.start();
    t2.start();
}
}

答案 7 :(得分:0)

这是我的解决方案,没有任何等待或通知。 wait()和notify()/ notifyAll(),
 我没有看到任何理由将它们用于此问题陈述。

package threading;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class EvenOddPrinting {

    int count=0;
    boolean isOdd = false;

    public static void main(String[] args) {
        ExecutorService exec = Executors.newCachedThreadPool();
        EvenOddPrinting obj = new EvenOddPrinting();
        exec.submit(new EvenPrinter(obj));
        exec.submit(new OddPrinter(obj));
        exec.shutdown();



    }

}

class EvenPrinter implements Runnable{
    EvenOddPrinting obj;
    public EvenPrinter(EvenOddPrinting obj) {
        this.obj=obj;
    }

    @Override
    public void run() {
        while(obj.count < 100){
            if(!obj.isOdd){
                System.out.println("Even:"+obj.count);
                obj.count++;
                obj.isOdd = true;
            }
        }

    }
}


class OddPrinter implements Runnable{

    EvenOddPrinting obj;
    public OddPrinter(EvenOddPrinting obj) {
        this.obj = obj;
    }

    @Override
    public void run() {
        while(obj.count < 100){
            if(obj.isOdd){
                System.out.println("Odd:"+obj.count);
                obj.count++;
                obj.isOdd = false;
            }
        }
    }
}

答案 8 :(得分:0)

使用Lock界面纠正了您的代码:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class NumberPrinter implements Runnable {
    private Lock lock;
    private Condition condition;
    private String type;
    private static boolean oddTurn = true;

    public NumberPrinter(String type, Lock lock, Condition condition) {
        this.type = type;
        this.lock = lock;
        this.condition = condition;
    }

    public void run() {
        int i = type.equals("odd") ? 1 : 2;
        while (i <= 10) {
            if (type.equals("odd"))
                printOdd(i);
            if (type.equals("even"))
                printEven(i);
            i = i + 2;
        }
    }

    private void printOdd(int i) {
        // synchronized (lock) {
        lock.lock();
        while (!oddTurn) {
            try {
                // lock.wait();
                condition.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(type + " " + i);
        oddTurn = false;
        // lock.notifyAll();
        condition.signalAll();
        lock.unlock();
    }

    // }

    private void printEven(int i) {
        // synchronized (lock) {
        lock.lock();
        while (oddTurn) {
            try {
                // lock.wait();
                condition.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(type + " " + i);
        oddTurn = true;
        // lock.notifyAll();
        condition.signalAll();
        lock.unlock();
    }

    // }

    public static void main(String[] args) {
        Lock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        Thread odd = new Thread(new NumberPrinter("odd", lock, condition));
        Thread even = new Thread(new NumberPrinter("even", lock, condition));
        odd.start();
        even.start();
    }
}

答案 9 :(得分:0)

public class Number_Thread extends Thread {

String thread;
int limit;

public Number_Thread(String thread,int limit){
    this.thread=thread;
    this.limit=limit;
                                             }

Object lock=new Object();

public  void run()
{

    synchronized (lock) 
    {

          //------------------- "print even"--------------------//

      if(thread.equals("even"))
        {
            for (int i = 2; i <=limit; i+=2) 
            {

                 System.out.println(thread+" thread "+i);
            try {

            lock.wait(1000);
                 continue;

                }
              catch (InterruptedException e) {}
            }
            lock.notifyAll();
        }

         //------------------- "print odd"--------------------//

    if(thread.equals("odd"))
         {
         for (int i = 1; i <=limit; i+=2) 
             {
                System.out.println(thread+" thread  "+i);
            try {

                lock.wait(1000);
                    continue;
                }
            catch (InterruptedException e) {}
            }
            lock.notifyAll();
         }
      }
   }
}

     //------------------thread creater class------------------//
import java.util.Scanner;

public class Main_Thread {
private static Scanner s;
    public static void main(String[] args) throws InterruptedException {
        System.out.print("enter limit:\t ");
        s=new Scanner(System.in);
    int n=s.nextInt();
     s.close();
    Thread t1=new Number_Thread("even",n);
    Thread t2=new Number_Thread("odd",n);
    t2.start();
    Thread.sleep(100);
    t1.start();

 }

}

限制5的输出:

输入限制:5

奇数线程1

连线程2

奇数话题3

连线程4

奇数线程5

答案 10 :(得分:0)

我已经以这样的方式实现了,基于这个参数,不会产生任何线程,并且会以循环方式相应的no。 即,如果线程数为3,则线程1将打印1,4 ...;线程2将打印2,5,......并且线程3将打印3,6 ......

public class ThreadSynchronizer
{

    public static void main(String[] args)
    {
    // BASED ON THE ARGUMENT MULTIPLE THREADS WILL BE CREATED AND EACH WILL PRINT ITS RESPECTIVE NO
    // IE, IF THREAD COUNT IS 3, THREAD 1 WILL PRINT 1,4 ..., THREAD2 WILL PRINT 2,5,... AND THREAD3 WILL PRINT 3,6...
    // LIMITED THE DISPLAY TO 1000 NOS
    int threadCnt = Integer.parseInt(args[0]);

    ReentrantLock lckArray[] = new ReentrantLock[threadCnt + 1];

    for (int i = 0; i < threadCnt + 1; i++)
    {
        ReentrantLock lck = new ReentrantLock();
        lck.lock();
        lckArray[i] = lck;
    }

    for (int i = 0; i < threadCnt; i++)
    {
        Thread th = new Thread(new Printer(lckArray, i + 1));
        th.start();
    }

    for (int i = 1; i < threadCnt + 1; i++)
    {
        lckArray[i].unlock();

        while (!lckArray[i].isLocked())
        {

        }
    }
    lckArray[0].unlock();
    }
}

class Printer implements Runnable
{

    private ReentrantLock[] lckArray;
    private int index;

    Printer(ReentrantLock[] lckArray, int startValue)
    {
    this.lckArray = lckArray;
    this.index = startValue;
    }

    @Override public void run()
    {
    ReentrantLock prevLock = null;
    int printCounter = index;

    for (int counter = 0; printCounter <= 1000; counter++)
    {
        int remCounter = counter % lckArray.length;
        int incCounter = lckArray.length - remCounter;
        int indexPostion = index + incCounter;
        int curElementIndex = indexPostion % lckArray.length;

        lckArray[curElementIndex].lock();
        if (prevLock != null)
        prevLock.unlock();
        prevLock = lckArray[curElementIndex];

        if (curElementIndex == 0)
        {
        System.out.println("Printed by Thread " + index + " " + printCounter);
        printCounter = printCounter + lckArray.length - 1;
        }

    }

    if (prevLock != null)
    {
        if (prevLock.isHeldByCurrentThread())
        prevLock.unlock();
    }

    }

}

答案 11 :(得分:0)

两个线程的程序,交替打印奇数和偶数。

#使用“对象锁定”概念实现。

class Increment{
private int count;
    public void increment(){
        count++;
        System.out.println(Thread.currentThread().getName()+"::::::::::::::::::"+count);
    }
}


class SimpleThread extends Thread{
 
 Increment obj = null;
 
 SimpleThread(Increment obj){
    this.obj=obj;
 }  
 
 public void run(){
     try {
    Thread.sleep(100);
         while(true){
            synchronized(obj){
                   obj.increment();
                   Thread.sleep(1000);
                   obj.notify();
                   obj.wait();  
            }
         }
     } catch(InterruptedException ie) {
        ie.printStackTrace(); 
     }
 } 
 
}

public class Main
{
    public static void main(String[] args) {
        
        Increment increment = new Increment();
        SimpleThread t1 = new SimpleThread(increment);
        SimpleThread t2 = new SimpleThread(increment);
       
        t1.start();
        t2.start();

        System.out.println(Thread.currentThread().getName()+"::::::::::::::"+"Hello World");
        System.out.println(Runtime.getRuntime().availableProcessors()+"::::::::::::::"+"CORE SIZE");
    }
}

答案 12 :(得分:0)

我以一种非常简单的方式(从1到40)实现了它

public class EvenOddProblem {

    public static void main(String[] args) {
        Printer p = new Printer();
        EvenThread enenThread = new EvenThread(p);
        OddThread oddThread = new OddThread(p);
        new Thread(enenThread).start();
        new Thread(oddThread).start();

    }

}

class EvenThread implements Runnable {
    private Printer printer;

    public EvenThread(Printer p) {
        printer = p;
    }

    @Override
    public void run() {
        try {
            int i = 0;
            while (true) {
                if (i == 20)
                    break;
                i++;

                printer.evenPrintEven();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

class OddThread implements Runnable {
    private Printer printer;

    public OddThread(Printer p) {
        printer = p;
    }

    @Override
    public void run() {
        int i = 0;
        try {
            while (true) {
                if (i == 20)
                    break;
                i++;
                printer.evenPrintOdd();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

class Printer {
    private static volatile Integer i = 1;

    public synchronized void evenPrintOdd() throws InterruptedException {
        while (i % 2 == 0) {
            wait();
        }
        System.out.println(i);
        i++;
        notifyAll();
    }

    public synchronized void evenPrintEven() throws InterruptedException {
        while (!(i % 2 == 0)) {
            wait();
        }
        System.out.println(i);
        i++;
        notifyAll();
    }
}