借助2个线程打印自然序列(1个打印均匀,2个打印奇数)

时间:2013-09-14 07:53:44

标签: java multithreading

我已经厌倦了这个问题,最后我有些疑惑。请帮帮我

怀疑:如果任何线程处于等待状态,并且没有其他线程通知该线程,那么它是否永远不会结束?即使在使用wait(长毫秒)之后。

对于代码:我的要求来自代码(请参阅我的代码):

a:应该打印“Even Thread Finish”和“Odd Thread Finish”(订单不是imp,但必须同时打印)

b:同样在main函数中应该打印“Exit Main Thread”

实际发生了什么:   经过大量的运行后,在某些情况下,它会打印“Even Thread Finish”然后挂起,反之亦然。在某些情况下,它会打印两者。

它也从不打印“退出主线”。

那么如何修改代码,所以它必须打印所有3个语句。(当然“Exit Main ..”在最后,因为我使用join for main。)

简而言之:主要开始 - > t1开始 - > t2开始,,那我需要t2 / t1完成 - >主要结束。

请帮我解决这个问题

这是我的代码:

import javax.sql.CommonDataSource;

public class ThreadTest {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Share commonObj = new Share();

        Thread even = new Thread(new EvenThread(commonObj));

        Thread odd = new Thread(new OddThread(commonObj));

        even.start();

        odd.start();

        try {
            Thread.currentThread().join();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        System.out.println("Exit Main Thread");

    }

}

class EvenThread implements Runnable {

    private Share commShare;
    public EvenThread(Share obj) {
        // TODO Auto-generated constructor stub
        this.commShare = obj;
    }

    private int number = 2;

    public void run() {
        System.out.println("Even Thread start");
        while (number <= 50) {
            if (commShare.flag == true) {
                System.out.println("Even Thread" + number);
                number += 2;
                commShare.flag = false;
                synchronized(commShare) {
                    try {
                        commShare.notify();
                        commShare.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    commShare.notify();
                }

            } else {
                synchronized(commShare) {
                    try {
                        commShare.notify();
                        commShare.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    commShare.notify();
                }
            }

        }

        System.out.println("Even Thread Finish");
    }
}


class OddThread implements Runnable {

    private int number = 1;
    private Share commShare;


    public OddThread(Share obj) {
        // TODO Auto-generated constructor stub
        this.commShare = obj;
    }



    public void run() {
        System.out.println("Odd Thread start");
        while (number <= 50) {
            if (commShare.flag == false) {
                System.out.println("Odd Thread :" + number);
                number += 2;
                commShare.flag = true;
                synchronized(commShare) {
                    try {
                        commShare.notify();
                        commShare.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    commShare.notify();
                }
            }
        }
        System.out.println("Odd Thread Finish");
    }
}

class Share {

    Share sharedObj;
    public boolean flag = false;
}

13 个答案:

答案 0 :(得分:3)

虽然这不是您问题的确切答案,但此实施方案可以替代您的问题。

public class EvenOddThreads {
    public static void main(String[] args) {
        Thread odd = new Thread(new OddThread(), "oddThread");

        Thread even = new Thread(new EvenThread(), "Even Thread");

        odd.start();
        even.start();
        try {
            odd.join();
            even.join();
            System.out.println("Main thread exited");
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
class OddThread implements Runnable{
    public void run() {
        synchronized (CommonUtil.mLock) {
            System.out.println(Thread.currentThread().getName()+"---> job starting");
            int i = 1;
            while(i<50){
                System.out.print(i + "\t");
                i = i + 2;
                CommonUtil.mLock.notify();
                try {
                    CommonUtil.mLock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("OddThread---> job completed");
            CommonUtil.mLock.notify();

        }
    }
}

class EvenThread implements Runnable{
    @Override
    public void run() {
        synchronized (CommonUtil.mLock) {
            System.out.println(Thread.currentThread().getName()+"---> job started");
            int i =2;
            while(i<50){
                System.out.print(i + "\t");
                i = i+2;
                CommonUtil.mLock.notify();
                try {
                    CommonUtil.mLock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("EvenThread---> job completed");
            CommonUtil.mLock.notify();
        }
    }
}

class CommonUtil{
    static final Object mLock= new Object();
}

输出:

oddThread---> job starting
1   Even Thread---> job started
2   3   4   5   6   7   8   9   10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  27  28  29  30  31  32  33  34  35  36  37  38  39  40  41  42  43  44  45  46  47  48  49  EvenThread---> job completed
OddThread---> job completed
Main thread exited

答案 1 :(得分:1)

好吧,我花了最后三个小时阅读Java sychronization tutorial(一个非常好的),然后是关于wait, notify and notifyAll的更多信息,我最终得到的程序使用N个线程来计算从A到B,将N设为2,你就有奇数和偶数。

pastebin

此外,我的程序没有任何评论,因此在尝试理解此代码之前,请务必阅读教程。

答案 2 :(得分:0)

这可能是对线程和锁定监视器的练习,但并行无关可以为您带来优势。

在代码中,当线程1(OddThread或EvenThread)结束工作并打印出“奇数线程完成”(或“偶数线程完成”)时,另一个线程2正在等待notify()或notifyAll()永远不会发生,因为第一次结束了。

您必须更改EvenThread和OddThread,在while循环后立即在commShare上添加带有通知调用的同步块。我删除了第二个if-branch,因为这样你就不会继续检查while条件,但很快就会等待commShare。

class EvenThread implements Runnable {
    private Share commShare;
    private int number = 2;

    public EvenThread(Share obj) {
        this.commShare = obj;
    }
    public void run() {
        System.out.println("Even Thread start");
        while (number <= 50) {
            synchronized (commShare) {
                if (commShare.flag) {
                    System.out.println("Even Thread:" + number);
                    number += 2;
                    commShare.flag = false;
                }
                commShare.notify();
                try {
                    commShare.wait();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
        synchronized (commShare) {
            commShare.notify();
            System.out.println("Even Thread Finish");
        }
    }
}

class OddThread implements Runnable {
    private int number = 1;
    private Share commShare;

    public OddThread(Share obj) {
        this.commShare = obj;
    }
    public void run() {
        System.out.println("Odd Thread start");
        while (number <= 50) {
            synchronized (commShare) {
                if (!commShare.flag) {
                    System.out.println("Odd Thread: " + number);
                    number += 2;
                    commShare.flag = true;
                }
                commShare.notify();
                try {
                    commShare.wait();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            }
        }
        synchronized (commShare) {
            commShare.notify();
            System.out.println("Odd Thread Finish");
        }
    }

最后,在主要内容中,您必须为您开始的每个线程加入。确定Thread.currentThread()只返回你的一个线程吗?我们已经启动了两个线程和那些我们应该加入的线程。

try {
      even.join();
      odd.join();
} catch (InterruptedException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
}

答案 3 :(得分:0)

  

它也从不打印“退出主线”。

这可能是因为你的线程正在等待notify()某人的锁定,但是由于错过信号或者没有人发信号通知他们,他们永远不会退出等待状态。为此,最好的解决方案是使用:

public final void wait(long timeout)
                throws InterruptedException
  

使当前线程等待,直到另一个线程调用   此对象的notify()方法或notifyAll()方法,或者   指定的时间已过。

这个重载的方法将等待其他线程通知特定的时间量,然后在超时发生时返回。因此,如果信号丢失,线程仍将继续工作。

  

注意:从等待状态返回后,请务必检查   再次 PRE-CONDITION ,因为它可能是Spurious Wakeup

这是我的程序风格,我为此编写了一段时间。

import java.util.concurrent.atomic.AtomicInteger;


public class Main {

    private static int range = 10;
    private static volatile AtomicInteger present = new AtomicInteger(0);
    private static Object lock = new Object();

    public static void main(String[] args) {
        new Thread(new OddRunnable()).start();
        new Thread(new EvenRunnable()).start();
    }

    static class OddRunnable implements Runnable{

        @Override
        public void run() {
            while(present.get() <= range){
                if((present.get() % 2) != 0){
                    System.out.println(present.get());
                    present.incrementAndGet();
                    synchronized (lock) {
                        lock.notifyAll();
                    }
                }else{
                    synchronized (lock) {
                        try {
                            lock.wait(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                            break;
                        }
                    }
                }
            }
        }
    }

    static class EvenRunnable implements Runnable{

        @Override
        public void run() {
            while(present.get() <= range){
                if((present.get() % 2) == 0){
                    System.out.println(present.get());
                    present.incrementAndGet();
                    synchronized (lock) {
                        lock.notifyAll();
                    }
                }else{
                    synchronized (lock) {
                        try {
                            lock.wait(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                            break;
                        }
                    }
                }
            }
        }
    }
}

看到解决方案,我保留了一个lock,用于通知偶数或奇数线程的可能性。如果偶数线程发现当前数字不均匀,则等待lock和 希望奇数线程在打印奇数时通知它。同样,它也适用于奇怪的线程。

我并不是说这是最好的解决方案,但这是第一次尝试时出现的,其他一些选项也是可能的。

另外我想指出这个问题虽然很好,但请记住,你没有做任何平行的事情。

答案 4 :(得分:0)

我不会投票使用wait()notify().使用waitnotify可以通过semaphore等更复杂的工具来完成这些工作。 },countDownLatchCyclicBarrier。您可以在项目编号为69 prefer concurrency utilities to wait and notify的着名书籍Effective java中找到此建议。

即使在这种情况下,我们根本不需要这些东西,我们可以通过简单的volatile boolean变量实现此功能。并且用于停止线程最好的方法是使用interrupt。经过一定的时间或某些预定义条件后,我们可以中断线程。请查看我的附件:

用于打印偶数的第1行:

public class MyRunnable1 implements Runnable
{
    public static volatile boolean isRun = false;
    private int k = 0 ;
    @Override
    public void run() {
        while(!Thread.currentThread().isInterrupted()){
            if(isRun){
                System.out.println(k);
                k+=2;
                isRun=false;
                MyRunnable2.isRun=true;
            }
        }
    }
}

线程2用于打印偶数:

public class MyRunnable2 implements Runnable{
    public static volatile boolean isRun = false;
    private int k = 1 ;
    @Override
    public void run() {
        while(!Thread.currentThread().isInterrupted()){
            if(isRun){
                System.out.println(k);
                k+=2;
                isRun=false;
                MyRunnable1.isRun=true;
            }
        }
    }
}

现在驱动上述主题的主要方法

public class MyMain{
    public static void main(String[] args) throws InterruptedException{
        Thread t1 = new Thread(new MyRunnable1());
        Thread t2 = new Thread(new MyRunnable2());
        MyRunnable1.isRun=true;
        t1.start();
        t2.start();
        Thread.currentThread().sleep(1000);
        t1.interrupt();
        t2.interrupt();
    }
}

可能有些地方你需要改变一点这只是一个骨架实现。希望它有所帮助,如果您需要别的东西,请告诉我。

答案 5 :(得分:0)

public class PrintNumbers {

    public static class Condition {
        private boolean start = false;
        public boolean getStart() {
            return start;
        }

        public void setStart(boolean start) {
            this.start = start;
        }
    }

    public static void main(String[] args) {

        final Object lock = new Object();
        // condition used to start the odd number thread first
        final Condition condition = new Condition();

        Thread oddThread = new Thread(new Runnable() {
            public void run() {
                synchronized (lock) {
                    for (int i = 1; i <= 10; i = i + 2) { //For simplicity assume  only printing till 10;
                        System.out.println(i);
                        //update condition value to signify that odd number thread has printed first
                        if (condition.getStart() == false) {
                            condition.setStart(true);
                        }
                        lock.notify();
                        try {
                            if (i + 2 <= 10) { 
                                lock.wait(); //if more numbers to print, wait;
                            }
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }

        });

        Thread evenThread = new Thread(new Runnable() {
            public void run() {
                synchronized (lock) {
                    for (int i = 2; i <= 10; i = i + 2) { //For simplicity assume only printing till 10;
                        // if thread with odd number has not printed first, then wait
                        while (condition.getStart() == false) {
                            try {
                                lock.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        System.out.println(i);
                        lock.notify();
                        try {
                            if (i + 2 <= 10) { //if more numbers to print, wait;
                                lock.wait();
                            }
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }

        });

        oddThread.start();
        evenThread.start();

    }

}

答案 6 :(得分:0)

I have done it this way and its working...

class Printoddeven{

public synchronized void print(String msg){
    try {
        if(msg.equals("Even"))
        {
        for(int i=0;i<=10;i+=2){
            System.out.println(msg+" "+i);
            Thread.sleep(2000);
            notify();
            wait();
        }
        }

        else{
            for(int i=1;i<=10;i+=2){
                System.out.println(msg+" "+i);
                Thread.sleep(2000);
                notify();
                wait();
            }
        }

    } catch (Exception e) {

        e.printStackTrace();
    }
}

}

class PrintOdd extends Thread{
Printoddeven oddeven;
public PrintOdd(Printoddeven oddeven){
    this.oddeven=oddeven;
}

public void run(){
    oddeven.print("ODD");

}

}

class PrintEven extends Thread{
Printoddeven oddeven;
public PrintEven(Printoddeven oddeven){
    this.oddeven=oddeven;
}

public void run(){
    oddeven.print("Even");

}

}



public class mainclass 
{

public static void main(String[] args) 
{

    Printoddeven obj = new Printoddeven();//only one object  
    PrintEven t1=new PrintEven(obj);  
    PrintOdd t2=new PrintOdd(obj);  
    t1.start();  
    t2.start();  

}
}

答案 7 :(得分:0)

我使用25个线程的ReentrantLock做到了。一个线程打印一个号码,它将通知其他人。

public class ReentrantLockHolder 
{
    private Lock lock;

    private Condition condition;

    public ReentrantLockHolder(Lock lock )
    {
        this.lock=lock;
        this.condition=this.lock.newCondition();
    }

    public Lock getLock() {
        return lock;
    }

    public void setLock(Lock lock) {
        this.lock = lock;
    }

    public Condition getCondition() {
        return condition;
    }

    public void setCondition(Condition condition) {
        this.condition = condition;
    }
}
public class PrintThreadUsingReentrantLock implements Runnable
{
    private ReentrantLockHolder currHolder;

    private ReentrantLockHolder nextHolder;

    private PrintWriter writer;

    private static int i=0;

    public PrintThreadUsingReentrantLock(ReentrantLockHolder currHolder, ReentrantLockHolder nextHolder ,PrintWriter writer)
    {
        this.currHolder=currHolder;
        this.nextHolder=nextHolder;
        this.writer=writer;
    }

    @Override
    public void run() 
    {
        while (true) 
        {
            writer.println(Thread.currentThread().getName()+ " "+ ++i);

            try{
                nextHolder.getLock().lock();
                nextHolder.getCondition().signal();
            }finally{
                nextHolder.getLock().unlock();  
            }

            try {
                currHolder.getLock().lock();
                currHolder.getCondition().await();
            }catch (InterruptedException e) 
            {
                e.printStackTrace();
            }
            finally{
                currHolder.getLock().unlock();
            }
        }
    }
}
public static void main(String[] args) 
    {
        PrintWriter printWriter =null;
        try {
                printWriter=new PrintWriter(new FileOutputStream(new File("D://myFile.txt")));
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        ReentrantLockHolder obj[]=new ReentrantLockHolder[25];
        for(int i=0;i<25;i++)
        {
            obj[i]=new ReentrantLockHolder(new ReentrantLock());
        }

        for(int i=0;i<25;i++)
        {
            Thread t1=new Thread(new PrintThreadUsingReentrantLock(obj[i], obj[i+1 == 25 ? 0 : i+1],printWriter ),"T"+i );
            t1.start();
        }
    }

答案 8 :(得分:0)

我尝试了类似的东西,其中线程1打印奇数,线程2以正确的顺序打印偶数,并且当打印结束时,将打印您建议的所需消息。请看一下这段代码

package practice;


class Test {

  private static boolean oddFlag = true;
  int count = 1;

  private void oddPrinter() {
    synchronized (this) {
      while(true) {
        try {
          if(count < 10) {
            if(oddFlag) {
              Thread.sleep(500);
              System.out.println(Thread.currentThread().getName() + ": " + count++);
              oddFlag = !oddFlag;
              notifyAll();
            }
            else {
              wait();
            }
          }
          else {
            System.out.println("Odd Thread finished");
            notify();
            break;
          }
        }
        catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    }
  }

  private void evenPrinter() {
    synchronized (this) {
      while (true) {
        try {
          if(count < 10) {
            if(!oddFlag) {
              Thread.sleep(500);
              System.out.println(Thread.currentThread().getName() + ": " + count++);
              oddFlag = !oddFlag;
              notify();
            }
            else {
              wait();
            }
          }
          else {
            System.out.println("Even Thread finished");
            notify();
            break;
          }
        }
        catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    }
  }


  public static void main(String[] args) throws InterruptedException{
    final Test test = new Test();

    Thread t1 = new Thread(new Runnable() {
      public void run() {
        test.oddPrinter();
      }
    }, "Thread 1");

    Thread t2 = new Thread(new Runnable() {
      public void run() {
        test.evenPrinter();
      }
    }, "Thread 2");

    t1.start();
    t2.start();

    t1.join();
    t2.join();

    System.out.println("Main thread finished");
  }
}

答案 9 :(得分:0)

package test;

public class Interview2 {

public static void main(String[] args) {
    Obj obj = new Obj();

    Runnable evenThread = ()-> {
        synchronized (obj) {
            for(int i=2;i<=50;i+=2) {
                while(!obj.printEven) {
                    try {
                        obj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }                   
                }
                System.out.println(i);
                obj.printEven = false;
                obj.notify();
            }
        }           
    };
    Runnable oddThread = ()-> {
        synchronized (obj) {
            for(int i=1;i<=49;i+=2) {
                while(obj.printEven) {
                    try {
                        obj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }                   
                }
                System.out.println(i);
                obj.printEven = true;
                obj.notify();
            }
        }
    };      
    new Thread(evenThread).start();
    new Thread(oddThread).start();
   }
}
class Obj {
  boolean printEven;
}

答案 10 :(得分:0)

这是非常通用的解决方案。它使用信号量在线程之间进行信令。 这是一般的解决方案,其中N个线程依次依次打印M个自然数。 也就是说,如果我们有3个线程并且要打印7个自然数,则输出为:

线程1:1:

线程2:2

线程3:3

线程1:4

线程2:5

线程3:6

线程1:7

import java.util.concurrent.Semaphore;

/*
 * Logic is based on simple idea
 * each thread should wait for previous thread and then notify next thread in circular fashion
* There is no locking required
* Semaphores will do the signaling work among threads.
*/

public class NThreadsMNaturalNumbers {

private static volatile int nextNumberToPrint = 1;
private static int MaxNumberToPrint;

public static void main(String[] args) {

    int numberOfThreads = 2;
    MaxNumberToPrint = 50;

    Semaphore s[] = new Semaphore[numberOfThreads];

    // initialize Semaphores
    for (int i = 0; i < numberOfThreads; i++) {
        s[i] = new Semaphore(0);
    }

    // Create threads and initialize which thread they wait for and notify to
    for (int i = 1; i <= numberOfThreads; i++) {
        new Thread(new NumberPrinter("Thread " + i, s[i - 1], s[i % numberOfThreads])).start();
    }
    s[0].release();// So that First Thread can start Processing
}

private static class NumberPrinter implements Runnable {

    private final Semaphore waitFor;
    private final Semaphore notifyTo;
    private final String name;

    public NumberPrinter(String name, Semaphore waitFor, Semaphore notifyTo) {
        this.waitFor = waitFor;
        this.notifyTo = notifyTo;
        this.name = name;
    }

    @Override
    public void run() {

        while (NThreadsMNaturalNumbers.nextNumberToPrint <= NThreadsMNaturalNumbers.MaxNumberToPrint) {
            waitFor.acquireUninterruptibly();
            if (NThreadsMNaturalNumbers.nextNumberToPrint <= NThreadsMNaturalNumbers.MaxNumberToPrint) {
                System.out.println(name + " : " + NThreadsMNaturalNumbers.nextNumberToPrint++);
                notifyTo.release();
            }

        }
        notifyTo.release();
    }

}

}

答案 11 :(得分:0)

此类显示偶数:

public class EvenThreadDetails extends Thread{

    int countNumber;
     public EvenThreadDetails(int countNumber) {
        this.countNumber=countNumber;
    }
    @Override
    public void run()
    {
        for (int i = 0; i < countNumber; i++) {
            if(i%2==0)
            {
                System.out.println("Even Number :"+i);
            }
            try {
                Thread.sleep(2);
            } catch (InterruptedException ex) {
                // code to resume or terminate...
            }
        }
    }
}

    

此类显示奇数:

public class OddThreadDetails extends Thread {

    int countNumber;
     public OddThreadDetails(int countNumber) {
        this.countNumber=countNumber;
    }
    @Override
    public void run()
    {
        for (int i = 0; i < countNumber; i++) {
            if(i%2!=0)
            {
                System.out.println("Odd Number :"+i);
            }
            try {
                Thread.sleep(2);
            } catch (InterruptedException ex) {
                // code to resume or terminate...
            }       
        }
    }
}

这是主班:

public class EvenOddDemo {

    public static void main(String[] args) throws InterruptedException
    {
        Thread eventhread= new EvenThreadDetails(100);
        Thread oddhread=new OddThreadDetails(100);
        eventhread.start();
        oddhread.start();   
    }
}

答案 12 :(得分:-1)

public class Driver {
    static Object lock = new Object();

    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable() {
            public void run() {

                for (int itr = 1; itr < 51; itr = itr + 2) {
                    synchronized (lock) {
                        System.out.print(" " + itr);
                        try {
                            lock.notify();
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
                System.out.println("\nEven Thread Finish ");
            }
        });
        Thread t2 = new Thread(new Runnable() {
            public void run() {

                for (int itr = 2; itr < 51; itr = itr + 2) {
                    synchronized (lock) {
                        System.out.print(" " + itr);
                        try {
                            lock.notify();
                            if(itr==50)
                                break;
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
                System.out.println("\nOdd Thread Finish ");
            }
        });
        try {
            t1.start();
            t2.start();
            t1.join();
            t2.join();
            System.out.println("Exit Main Thread");
        } catch (Exception e) {

        }
    }
}