gpt4 book ai didi

java - 在Java中使用信号量

转载 作者:行者123 更新时间:2023-11-30 06:57:43 25 4
gpt4 key购买 nike

我感到内地向StackOverflow寻求学校帮助,但我已经用尽了资源,无法终生解决这一问题。对于我的类(class)之一,我需要了解如何在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许可进行初始化,以便数字线程将等待斜杠线程开始。

    另外两个警告:
  • 要使代码按示例输出所示工作,您还需要从每个打印的字符串中删除\n,否则每个字符都将位于不同的行上。但是,讲师可能希望每个字符都在不同的行上,并给您不好的示例输出。您必须猜测他真正想要的是什么。
  • 如果您想使代码防弹,则可能需要按照以下内容在System.out上进行同步:

    Synchronization and 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;,使逻辑和数字关系清楚明了。

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

    关于java - 在Java中使用信号量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33337492/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com