首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用信号量打印来自2个线程的备用输出

使用信号量打印来自2个线程的备用输出
EN

Stack Overflow用户
提问于 2017-05-08 01:46:16
回答 2查看 858关注 0票数 1

我正在学习信号量和多线程的一般用法,但我有点被卡住了。我有两个线程分别打印G和H,我的目标是交替每个线程的输出,使输出字符串如下所示;

代码语言:javascript
运行
复制
G
H
G
H
G
H

这两个类中的每个类都有一个类似于下面的布局

代码语言:javascript
运行
复制
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();
        }

    }

}

下面是我的主类

代码语言:javascript
运行
复制
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();

我得到的输出与我预期的结果相差太远。有谁能帮帮我吗?我是不是误用了信号灯?有什么帮助吗?

EN

回答 2

Stack Overflow用户

发布于 2017-05-08 03:07:18

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

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

代码语言:javascript
运行
复制
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());
            }
        }
    }
}

顺便说一句,可能还有另一个问题,因为System.out通常是一个操作系统缓冲区,你的操作系统可以按自己的顺序输出你的消息。

附注:你不应该同时继承Thread和实现Runnable

代码语言:javascript
运行
复制
public class ClassA extends Thread implements Runnable{

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

你应该启动一个线程,然后加入它,反之亦然。

代码语言:javascript
运行
复制
t1.start();
t2.join();
t2.start();
票数 0
EN

Stack Overflow用户

发布于 2017-05-08 07:02:18

正如其他人指出的那样,锁本身并不强制执行任何顺序,最重要的是,您不能确定线程何时启动(调用Thread.start()将在将来的某个时候启动线程,但这可能需要一段时间)。

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

下面是一个具有可重复结果的可运行示例类(在测试多线程时,拥有这样的类总是一件好事)。我将留给您去弄清楚它为什么以及如何工作。

代码语言:javascript
运行
复制
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();
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43834700

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档