2

私はこの質問にうんざりしていて、最終的にいくつかの疑問が生じました。私を助けてください

疑問: スレッドが待機状態にあり、他のスレッドがそのスレッドに通知していない場合、そのスレッドは決して終了しないのでしょうか? 待機(長いミリ秒)を使用した後でも。

コードの場合:コードからの私の要件は何ですか(私のコードを参照してください):

a : "Even Thread Finish" と "Odd Thread Finish" を印刷する必要があります (順序は imp ではありませんが、両方を印刷する必要があります)。

b: また、メイン関数で「Exit Main Thread」を出力する必要があります

実際に何が起こっているか: 多くの実行の後、場合によっては、「Even Thread Finish」と出力されてここでハングアップするか、その逆です。場合によっては、両方を印刷します。

また、「Exit Main Thread」は出力されません。

コードを変更する方法 、したがって、3つのステートメントすべてを出力する必要があります。

簡単に説明すると、メイン スタート -> 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;
}
4

13 に答える 13

1

さて、私は過去 3 時間Java 同期チュートリアル(非常に優れたチュートリアル) を読んだ後、 wait 、 notify 、および notifyAllに関する詳細情報を読みました。 2 奇数と偶数があります。

ペーストビン

また、私のプログラムにはコメントがまったくないので、このコードを理解する前に必ずチュートリアルを読んでください。

于 2013-09-14T13:00:07.517 に答える
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();

    }

}
于 2013-10-18T05:56:44.843 に答える
0

また、「Exit Main Thread」も出力されません。

これは、スレッドがロックで誰かが待機している可能性がありますが、notify()シグナルを逃したか、誰もシグナルを送っていないため、待機状態から抜け出せないためです。そのための最良の解決策は、次を使用することです。

public final void wait(long timeout)
                throws InterruptedException

別のスレッドがnotify()メソッドまたはnotifyAll()このオブジェクトのメソッドを呼び出すか、指定された時間が経過するまで、現在のスレッドを待機させます。

このオーバーロードされたメソッドは、他のスレッドが特定の時間通知するのを待ってから、タイムアウトが発生した場合に戻ります。そのため、シグナルが失われた場合でも、スレッドは作業を再開します。

注: 待機状態から戻った後は 、 Spurious Wakeupである可能性があるため、常にPRE-CONDITIONを再度確認してください。

これは、以前同じようにコーディングした私のフレーバーのプログラムです。

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その奇数を出力したときに奇数スレッドが通知することを期待します。同様に、奇数スレッドでも機能します。

これが最善の解決策であるとは言いませんが、これは最初の試行で得られたものであり、他のオプションもいくつか可能です。

また、この質問は練習としては良いことですが、そこで並行して何もしていないことに注意してください。

于 2013-09-14T12:20:20.250 に答える
0

私は 25 スレッドの ReentrantLock を使用してそれを行いました。1 つのスレッドが 1 つの番号を印刷すると、他の に通知されます。

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();
        }
    }
于 2016-03-04T07:21:12.143 に答える
0

これは、スレッドとロック モニターに関する演習になる可能性がありますが、並行して行うことでメリットが得られるものは何もありません。

スレッド1(OddThreadまたはEvenThread)が作業を終了し、「Odd Thread Finish」(または「Even Thread Finish」)を出力すると、コードで他のスレッド2がnotify()またはnotifyAll()を待っています。 1回目が終わったので。

EvenThread と OddThread を変更して、while サイクルの直後に commShare の通知呼び出しを使用して同期ブロックを追加する必要があります。2 番目の 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() があなたのスレッドの 1 つだけを返すことは確かですか? 2 つのスレッドと、参加すべきスレッドを開始しました。

try {
      even.join();
      odd.join();
} catch (InterruptedException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
}
于 2013-09-14T08:40:27.807 に答える