繁体   English   中英

在Java中使用信号量

[英]Using Semaphores in Java

我感到内地向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", '\\');
            }
        }
    }
}

我只需要添加“与信号量有关的语句”即可修改代码,以便程序反复打印出一个'/',后跟三位数字,然后再打印出一个'\\',再后跟两个字母。

他们给出的示例如下:

  /156\BA/376\YZ/654\JK/257\HG/445\DD…

任何帮助将不胜感激。 我通常很擅长自己学习,但是这些线程使我头晕! 谢谢!

我对这名教师的教学方法和编码习惯表示怀疑,但我会回答这个问题。 实际上,我认为问题过于复杂的事实使我更愿意回答这个问题,而不是让您自己解决。

该示例有点违反直觉,因为线程没有用于其正常目的,即允许并发执行,而只是作为理解信号量的练习。 结果,信号量也将不得不以某种非标准的方式使用,作为线程之间的信号,而不是为了正常使用它们来管理资源。 您将了解信号在这种人为情况下的工作原理,但可能最终无法理解信号在正常情况下的用法。 但是,可以通过阅读Semaphore类上的Javadoc来解决此问题,因此请回到讲师的人为情况。

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

信号量对象应代表以下四件事:

  • 可以打印的数字
  • 已打印的数字(最近的正斜杠之后)
  • 可以打印的字符
  • 已打印的字符(最近的反斜杠之后)

PrintDigit.run()应该在打印每个数字之前从可用的数字信号获得许可。 允许数字可用信号灯将数字打印一次限制为三个。 在打印数字后,该方法应从数字打印的信号量中释放一个许可-注意,而不是可用的数字信号量-表示已经打印了一个数字。 我确定您可以弄清楚PrintLetter.run()应该做什么。 顺便提一句,线程正在获取一个信号量但释放了一个不同的信号量,这是设计此示例的一种方式。 通常,线程释放它们获取的相同信号量。

PrintSlashes.run()应该在打印斜杠后从可用的数字信号灯中释放三个许可,然后在打印反斜杠之前从数字的已打印的信号灯中获取三个许可。 释放可用的三位数允许PrintDigit线程打印三位数,并且等待获取已打印的三位数可确保在继续操作之前先打印三位数。 同样,您应该能够弄清楚在打印反斜杠之后会发生什么。

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

另外两个警告:

  1. 要使代码按示例输出所示工作,您还需要从每个打印的字符串中删除\\n ,否则每个字符将位于不同的行上。 但是,讲师可能希望每个字符都在不同的行上,并给您不好的示例输出。 您必须猜测他真正想要的。

  2. 如果要使代码更安全,则可能需要按照以下内容在System.out上进行同步:

    同步和System.out.println

    但是,您的教练在本练习中可能并不关心该问题。

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

  • 不应使用通配符导入,因为您没有从并发包中使用很多类。 我认为,绝对不应使用通配符导入。 通配符的导入会使得很难看清类的来源,从而削弱了代码的可读性,而可读性是代码最重要的一个方面。

  • 有意义的常量,例如此代码中的“ 10”,“ 26”,“ 36”和“ 37”,不应写为文字,而应使用已定义的常量,例如, static final int NUMBER_OF_DIGITS = 10; 然后,代码本身可以使用符号NUMBER_OF_DIGITS ,使其更易读且也更易于维护,因为您可以轻松地更改常量的值-例如,如果要将代码转换为八进制,则可以更改为8-而无需担心会错过常量的某些出现。

  • 当有意义的常量具有逻辑关系时,尤其不应将它们写为文字。 在这种情况下,即使static final int NUMBER_OF_CHARACTERS = 36也不是一个好习惯; 它应该是static final int NUMBER_OF_CHARACTERS = NUMBER_OF_DIGITS + NUMBER_OF_LETTERS; ,使逻辑和数字关系清晰明了。

您是否真的要在上交的作业中进行这些更正,取决于您认为教师对得到良好的更正的反应。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM