Java:一个线程需要等待其他线程完成

时间:2013-08-26 17:19:27

标签: java multithreading

我有以下用例。假设它可以在JAVA 6上运行,任何人都可以建议方法 t1()的良好实现吗?我试着想到使用wait()和notify()完成这个,但无法得到正确的解决方案。任何帮助将不胜感激。 (请注意,这两种方法 t1() m1()都将在不同的线程中调用)

 class Test
 {

   static volatile int flag = 0;

   public static void t1()
   {
           //This method will be called in a Thread called T2
           /*This method must wait for flag to become 1. As soon it
             becomes 1 this must return. However it should wait for maximum 
             n seconds. After that even if flag is 0 it must return.*/
   }



   public static void m1()
   {
           //This method will be called in a Thread called T1
           flag = 1;
   }
} 

这就是我尝试t1()

的实现
   public static void t1() throws InterruptedException
   {
          while(flag == 0)
          {
               Thread.currentThread().sleep(100);
          }
   }

以上工作但问题是超时没有实现,而循环似乎没那么好。

4 个答案:

答案 0 :(得分:3)

使用CountDownLatch。在使用count计数运行的任何线程之前初始化它。您的代码将如下所示:

class Test
 {

   static CountDownLatch latch = new CountDownLatch(1);

   public static void t1()
   {
           //This method will be called in a Thread called T2
           /*This method must wait for flag to become 1. As soon it
             becomes 1 this must return. However it should wait for maximum 
             n seconds. After that even if flag is 0 it must return.*/
           latch.await(1L,TimeUnit.SECONDS);
           //your remaining logic
   }



   public static void m1()
   {
          //your logic
          latch.countDown();
   }
}

CountDownLatch是一个有点修改,增强(例如超时选项),可以说更容易理解Semaphore的实现 - 一种广泛用于跨数字线程同步的基本结构语言(不仅是Java)。在比较Wikipedia对Java实现的引用时请注意以下内容:

  • P / wait()对应await(),区别在于await()不会更改count值。
  • V / signal()对应countDown(),区别在于countDown()计数向下,而不是向上(显然)。

答案 1 :(得分:2)

使用CountDownLatch

private static CountDownLatch countDownLatch = new CountDownLatch(1);

public static void t1() throws InterruptedException {
    countDownLatch.await(1000L, TimeUnit.MILLISECONDS);
    System.out.println("t2");
}

public static void m1() throws InterruptedException {
    System.out.println("t1");

    // you can simulate some activity
    Thread.sleep(500);
    countDownLatch.countDown();
}

运行t1()的线程必须等待一秒钟。

public static void main(String[] args) throws IOException, ParseException {
    Thread t1 = new Thread(new Runnable() {

        @Override
        public void run() {
            try {
                test.Test.m1();
            } catch (InterruptedException e) {
                // do something
            }
        }
    });

    Thread t2 = new Thread(new Runnable() {

        @Override
        public void run() {
            try {
                test.Test.t1();
            } catch (InterruptedException e) {
                // do something
            }
        }
    });
    t2.start();
    t1.start();
}

这在静态上下文中是一个坏主意,但是因为其他类可以访问它并且可能调用方法,这会搞砸锁。

答案 2 :(得分:0)

您可以投票,直到条件满足为止。我认为使用Thread.sleep(long time)更实际,而不是在检查之间使用Thread.yield()

public static void t1()
{
    while (flag == 0)
    {
        Thread.yield();
    }
}

答案 3 :(得分:0)

使用CountDownLatch

的叙述性完整示例
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public class Race {

    public static void main(String[] args) {
        boolean flag=true; //set false to see other behavior
        if (flag) {
            startRace(5L, 2L);
        } else {
            startRace(2L, 5L);
        }
    }

    private static void startRace(final long s1, final long s2) {
        new Thread() {
            @Override
            public void run() {
                Test.t1(s1);
            }
        }.start();
        new Thread() {
            @Override
            public void run() {
                Test.t2(s2);
            }
        }.start();
    }
}

class Test {

    static volatile int flag = 0;

    static CountDownLatch L = new CountDownLatch(1);

    public static void t1(long n) {
        await(n);
        logic1();
        L.countDown(); // comment to wait till end

    }

    public static void t2(long n) {
        await(n);
        logic2();
        L.countDown();
    }

    private static void logic1() {
        if (flag == 0) {
            System.out.println(Thread.currentThread()
                    + ": Flag Couldnt be set in time");
        } else {
            System.out.println(Thread.currentThread() + ": Flag set in time");
        }
    }

    private static void logic2() {
        flag = 1;
        System.out.println(Thread.currentThread() + ": Flag Set");
    }

    private static void await(long n) {
        waitMsg(n);
        try {
            if (L.await(n, TimeUnit.SECONDS)) {
                waitOverBefore(n);
            } else {
                waitOver(n);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    private static void waitOverBefore(long n) {
        System.out.println(Thread.currentThread() + ": Waiting Over before "
                + n + " seconds");
    }

    private static void waitOver(long n) {
        System.out.println(Thread.currentThread() + ":" + n
                + " seconds Waiting Over");
    }

    private static void waitMsg(long n) {
        System.out.println(Thread.currentThread() + ":Waiting for " + n
                + " seconds");
    }

}

输出1

Thread[Thread-0,5,main]:Waiting for 5 seconds
Thread[Thread-1,5,main]:Waiting for 2 seconds
Thread[Thread-1,5,main]:2 seconds Waiting Over
Thread[Thread-1,5,main]: Flag Set
Thread[Thread-0,5,main]: Waiting Over before 5 seconds
Thread[Thread-0,5,main]: Flag set in time

输出2

Thread[Thread-1,5,main]:Waiting for 5 seconds
Thread[Thread-0,5,main]:Waiting for 2 seconds
Thread[Thread-0,5,main]:2 seconds Waiting Over
Thread[Thread-0,5,main]: Flag Couldnt be set in time
Thread[Thread-1,5,main]: Waiting Over before 5 seconds
Thread[Thread-1,5,main]: Flag Set