Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jquery-ui/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Java中使用信号量_Java_Multithreading_Semaphore_Thread Synchronization - Fatal编程技术网

在Java中使用信号量

在Java中使用信号量,java,multithreading,semaphore,thread-synchronization,Java,Multithreading,Semaphore,Thread Synchronization,我觉得在学校向StackOverflow寻求帮助很内疚,但我已经耗尽了我的资源,无法用我的一生来解决这个问题。对于我的一个类,我需要理解如何在Java中构造和正确使用信号量。其中一个练习具有以下代码: import java.lang.Thread; import java.util.concurrent.*; public class ThreadSync { private static boolean runFlag = true; public static void

我觉得在学校向StackOverflow寻求帮助很内疚,但我已经耗尽了我的资源,无法用我的一生来解决这个问题。对于我的一个类,我需要理解如何在Java中构造和正确使用信号量。其中一个练习具有以下代码:

import java.lang.Thread;
import java.util.concurrent.*;

public class ThreadSync
{
    private static boolean runFlag = true;

    public static void main( String[] args ) {
        Runnable[] tasks = new Runnable[37];
        Thread[] threads = new Thread[37];
        // create 10 digit threads
        for (int d=0; d<10; d++) {
            tasks[d] = new PrintDigit(d);
            threads[d] = new Thread( tasks[d] );
            threads[d].start();
        }
        // create 26 letter threads
        for (int d=0; d<26; d++) {
            tasks[d+10] = new PrintLetter((char)('A'+d));
            threads[d+10] = new Thread( tasks[d+10] );
            threads[d+10].start();
        }
        // create a coordinator thread
        tasks[36] = new PrintSlashes();
        threads[36] = new Thread( tasks[36] );
        threads[36].start();

        // Let the threads to run for a period of time
        try {
            Thread.sleep(50);
        }
        catch (InterruptedException ex) {
            ex.printStackTrace();
        }
        runFlag = false;

        // Interrupt the threads
        for (int i=0; i<37; i++) threads[i].interrupt();
    }

    public static class PrintDigit implements Runnable 
    {
        int digit;
        public PrintDigit(int d) { digit=d; }
        public void run(){
            while (runFlag) {
                System.out.printf( "%d\n", digit);
            }
        }
    }
    public static class PrintLetter implements Runnable 
    {
        char letter;
        public PrintLetter(char c) { letter=c; }
        public void run(){
            while (runFlag) {
                System.out.printf( "%c\n", letter);
            }
         }
    }
    public static class PrintSlashes implements Runnable 
    {
        public void run(){
            while (runFlag) {
                System.out.printf( "%c\n", '/');
                System.out.printf( "%c\n", '\\');
            }
        }
    }
}

任何帮助都将不胜感激。我通常很擅长自学,但这些线索让我头晕目眩!谢谢

我质疑这位讲师的教学方法和编码实践,但我会回答这个问题。事实上,我认为这个问题过于复杂,这让我更愿意回答它,而不是让你自己去想

这个例子有点违反直觉,因为线程不是用于其正常用途,即允许并发执行,而只是作为理解信号量的练习。因此,信号量还必须以某种非标准的方式使用,作为线程之间的信号,而不是用于管理资源的正常使用。您将理解信号量在这种人为的情况下是如何工作的,但最终可能无法理解它们在正常情况下是如何使用的。然而,这可以通过阅读Semaphore类上的Javadoc来解决,所以回到您的讲师的精心设计的案例

很明显,运行PrintSlashes.run的线程旨在充当管理器,确定何时运行数字线程以及何时运行字符线程。它需要告诉数字线程何时可以运行,并且需要告诉字符线程何时可以运行。此外,它需要知道何时打印了三个数字,何时打印了两个字符。这是需要传输的四条信息,最简单的模型是使用四个信号量对象

信号量对象应表示以下四个方面:

可打印的数字 最近一次正斜杠后打印的数字 可供打印的字符 最近一次反斜杠后打印的字符 PrintDigit.run应在打印每个数字之前从可用的数字信号灯获取许可证;这允许可用的数字信号限制一次打印三个数字。在打印数字后,该方法应该从打印的数字信号量(注意,而不是可用的数字信号量)中释放一个许可证,以指示已经打印了一个数字。我相信你一定能想出PrintLetter.run应该做什么。顺便说一句,线程正在获取一个信号量,但释放了一个不同的信号量,这是设计这个示例的方式之一;通常线程释放它们获取的相同信号量

PrintSlashes.run应在打印斜杠后从数字信号量中释放三个许可证,然后在打印反斜杠之前从数字信号量中获取三个许可证。释放可用的三位数字允许PrintDigit线程打印三位数字,等待获取打印的三位数字可确保在继续之前打印三位数字。同样,您应该能够了解在打印反斜杠后会发生什么

请注意,数字信号量对象应使用0许可证初始化,以便数字线程将等待斜杠线程启动

另外两个注意事项:

要使代码如示例输出所示工作,还需要从每个打印的字符串中删除\n,否则每个字符将位于不同的行上。但是,讲师可能希望每个字符位于不同的行上,并且给出了错误的示例输出。你得猜他到底想要什么

如果要使代码防弹,可能需要在System.out上同步,如中所述:

然而,在本练习中,您的讲师可能并不关心这个问题

最后,应进行以下更正,以修复代码中的其他错误做法:

不应使用通配符导入,因为您没有使用并发包中的很多类。在我看来,永远不应该使用通配符导入。通配符导入会降低代码的易读性,因为很难看到类来自何处,易读性是代码最重要的一个方面

有意义的常量,如本代码中的10、26、36和37,不应写为文字,而应使用已定义的常量,例如静态最终整数位数=10;。然后,代码本身就可以使用符号数字,使其更清晰,也更易于维护,因为您可以轻松地更改常量的值,例如,如果您想将代码转换为八进制,则可以将其更改为8,而无需担心会错过常量的某些出现

有意义的常量应该是 特别是当它们具有逻辑关系时,不能作为文字来编写。在这种情况下,即使是静态的最终整数(字符数=36)也不是好的做法;它应该是静态的最终整数字符数=数字数+字母数;,明确逻辑和数字关系


你是否真的想在交上来的作业中做出这些更正取决于你认为讲师对得到正确更正的反应。

那么,你是说信号量语句本质上是忙碌等待语句?你的评论肯定帮助我完成了这一点。唯一的问题是,charactersPrintedSemaphore应该用值2初始化,以便在启动程序之前通过PrintSlashes获取它,从而实现循环。除非我错过了什么!不管怎样,谢谢!说得好。我会更新答案。编辑:如果将charactersPrintedSemaphore的获取放在while循环的开头,则为true。如果它在while循环的末尾,那么它应该初始化为0。两种方法都有效。
  /156\BA/376\YZ/654\JK/257\HG/445\DD…