2017-05-07 39 views
1

我正在学习使用信号量和多线程的一般情况,但有点卡住了。我有两个线程分别打印G和H,我的目标是交替每个线程的输出,以便输出字符串是这样的;使用信号量从2个线程打印替代输出

G 
H 
G 
H 
G 
H 

每两个类都有类似下面

public class ClassA extends Thread implements Runnable{ 

    Semaphore semaphore = null; 
    public ClassA(Semaphore semaphore){ 

     this.semaphore = semaphore; 
    } 

    public void run() { 

     while(true) 
     { 
      try{ 
       semaphore.acquire(); 
       for(int i=0; i<1000; i++){ 
        System.out.println("F"); 

       } 
       Thread.currentThread(); 
       Thread.sleep(100); 
      }catch(Exception e) 
      { 
       System.out.println(e.toString()); 
      } 
      semaphore.release(); 
     } 

    } 

} 
下面

的一个布局,我的主类

public static void main(String[] args) throws InterruptedException { 

    Semaphore semaphore = new Semaphore(1); 

    ClassA clasA = new ClassA(semaphore); 
    Thread t1 = new Thread(clasA); 
    ClassB clasB = new ClassB(semaphore); 
    Thread t2 = new Thread(clasB); 
    t1.start(); 
    t2.join(); 
    t2.start(); 

我得到的输出是太不同我预期结果。任何人都可以帮助我吗?我误用了信号量吗?任何帮助?

+0

如果使用固有锁或重入锁或信号或什么不要紧,只是用锁不执行任何命令 –

+0

OK,请你提出一个前进道路,以获得预期的订单?你会说上面代码的弱点吗? – Jazztheman

回答

0

信号量不能帮你解决这样的任务。

据我所知,JVM不承诺线程执行的任何顺序。这意味着如果您运行多个线程,则一个线程可以连续执行多次,并且处理器的处理时间比任何其他处理器都多。因此,如果你想让你的线程以特定的顺序执行,那么对于最简单的例子,你可以创建一个静态布尔变量,它将为你的线程起一个切换器的作用。使用wait()和notify()方法将是更好的方法,并且Interface Condition将是我想的最好的方式。

import java.io.IOException; 

public class Solution { 
    public static boolean order; 

    public static void main(String[] args) throws IOException, InterruptedException { 
     Thread t1 = new ThreadPrint("G", true); 
     Thread t2 = new ThreadPrint("O", false); 
     t1.start(); 
     t2.start(); 
     t2.join(); 

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

} 

class ThreadPrint extends Thread { 

    private String line; 
    private boolean order; 

    public ThreadPrint(String line, boolean order) { 
     this.line = line; 
     this.order = order; 
    } 

    @Override 
    public void run() { 
     int z = 0; 
     while (true) { 
      try { 
       for (int i = 0; i < 10; i++) { 
        if (order == Solution.order) { 
         System.out.print(line + " "); 
         Solution.order = !order; 
        } 
       } 
       sleep(100); 
      } catch (Exception e) { 
       System.out.println(e.toString()); 
      } 
     } 
    } 
} 

BTW可以有另一个问题原因的System.out通常是一个操作系统缓冲区和您的操作系统可以输出在其自己的订单邮件。

P.S.您不应该继承Thread并同时实现Runnable

public class ClassA extends Thread implements Runnable{ 

因为Thread类已经实现了Runnable。您只能选择一种更适合您的目的的方式。

你应该开始一个线程然后加入到它,而不是反之亦然。

t1.start(); 
t2.join(); 
t2.start(); 
0

正如其他人所指出的那样,锁定本身不执行任何命令,并在此基础之上,你无法确定当一个线程开始(调用Thread.start()将在未来的某个时刻开始线程,但是这可能需要一段时间)。

但是,您可以使用锁定(如Semaphore)来执行订单。在这种情况下,可以使用两个信号量来打开和关闭线程(备用)。这两个线程(或Runnables)确实需要提前知道对方 - 线程可以“加入”派对的更加动态的方法将更加复杂。

在具有可重复结果的可运行示例类下面(测试多线程时总是一件好事)。我会让你知道为什么以及它是如何工作的。

import java.util.concurrent.*; 

public class AlternateSem implements Runnable { 

    static final CountDownLatch DONE_LATCH = new CountDownLatch(2); 
    static final int TIMEOUT_MS = 1000; 
    static final int MAX_LOOPS = 10; 

    public static void main(String[] args) { 

     ExecutorService executor = Executors.newCachedThreadPool(); 
     try { 
      AlternateSem as1 = new AlternateSem(false); 
      AlternateSem as2 = new AlternateSem(true); 
      as1.setAlternate(as2); 
      as2.setAlternate(as1); 
      executor.execute(as1); 
      executor.execute(as2); 
      if (DONE_LATCH.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 
       System.out.println(); 
       System.out.println("Done"); 
      } else { 
       System.out.println("Timeout"); 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } finally { 
      executor.shutdownNow(); 
     } 
    } 

    final Semaphore sem = new Semaphore(0); 
    final boolean odd; 
    AlternateSem other; 

    public AlternateSem(boolean odd) { 
     this.odd = odd; 
    } 

    void setAlternate(AlternateSem other) { this.other = other; } 
    void release() { sem.release(); } 
    void acquire() throws Exception { sem.acquire(); } 

    @Override 
    public void run() { 

     if (odd) { 
      other.release(); 
     } 
     int i = 0; 
     try { 
      while (i < MAX_LOOPS) { 
       i++; 
       other.acquire(); 
       System.out.print(odd ? "G " : "H "); 
       release(); 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     DONE_LATCH.countDown(); 
    } 
}