在一次采访中,我被要求使用两个而且只有两个线程来打印字符串1A2B3C。。。24X25Y26Z
,其中一条线只打印数字,另一条线只打印字母。我编写了以下代码:
public class App {
static volatile int x = 0;
static volatile boolean numPrinted = false;
static class NumThread implements Runnable {
@Override
public void run() {
while (x < 26) {
if (!numPrinted) {
System.out.print(x + 1);
numPrinted = true;
}
}
}
}
static class LetterThread implements Runnable {
@Override
public void run() {
while (x < 26) {
if (numPrinted) {
System.out.print((char) ('A' + x));
++x;
numPrinted = false;
}
}
}
}
public static void main(String[] args) {
Thread foo = new Thread(new NumThread());
Thread bar = new Thread(new LetterThread());
foo.start();
bar.start();
try {
foo.join();
bar.join();
} catch (InterruptedException ignored) {
}
System.out.println();
}
}
在大约10次运行中有1次,它将产生
1A2B3C4D5E6F7G8H9I10J11K12L13M14N15O16P17Q18R19S20T21U22V23W24X25Y26Z27
我的代码有什么并发问题?我故意避免原子整数。
只需使用一个共享变量(在本例中为numPrinted
)就可以更容易地解决这个问题。这表明哪个线程需要执行某些操作。线程本身可以跟踪它们的进度,等到需要打印某个内容时再打印,然后翻转对两个线程都可见的numPrinted
变量。这可能看起来像:
static volatile boolean numPrinted = false;
static class NumThread implements Runnable {
@Override
public void run() {
for (int number = 1; number <= 26; number++) {
// Wait until we need to print a number
while (numPrinted) {
Thread.yield(); //optional
};
// Print a number
System.out.print(number);
// Set flag that we printed a number
numPrinted = true;
}
}
}
static class LetterThread implements Runnable {
@Override
public void run() {
for (char letter = 'A'; letter <= 'Z'; letter++) {
// Wait until we need to print a letter
while (!numPrinted) {
Thread.yield(); //optional
}
// Print a letter
System.out.print(letter);
//set flag that we printed a letter
numPrinted = false;
}
}
}
您的程式码在两个类别成员x和NumPrted上有竞态条件。您可以尝试实作互斥锁和条件变数。以下是每次都能正确运作的Ada范例。
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
procedure Main is
protected traffic_Cop is
entry Nums (Val : Positive);
entry Alpha (Val : Character);
private
gate : Boolean := True;
end traffic_Cop;
protected body traffic_cop is
entry Nums (Val : Positive) when gate is
begin
Put (Item => Val, Width => 1);
gate := False;
end Nums;
entry Alpha (Val : Character) when not gate is
begin
Put (Val);
gate := True;
end Alpha;
end traffic_cop;
task printnums;
task printalpha;
task body printnums is
begin
for value in 1 .. 26 loop
traffic_cop.Nums (value);
end loop;
end printnums;
task body printalpha is
subtype chars is Character range 'A' .. 'Z';
begin
for value in chars loop
traffic_Cop.Alpha (value);
end loop;
end printalpha;
begin
null;
end Main;
该示例使用一个受保护对象和两个任务。Ada保护的对象受到保护,不受不适当的种族条件的影响。任务通常映射到操作系统线程。
受保护对象可以公开三种方法。
受保护函数隐式地建立并实现共享读锁,允许多个任务同时从受保护对象读取数据。
受保护的过程隐式地建立并实现独占读写锁,一次只允许一个任务无条件地读取或修改受保护对象内的数据。
受保护的条目隐式地建立并实现一个排他的读写锁和一个条目条件。只有当与条目相关联的边界条件计算为True时,调用条目的任务才能读取和/或修改受保护对象的内容。
上面的例子使用了两个条目。
受保护对象traffic_cop只包含一个变量,即名为gate的布尔值,该值被初始化为True。
受保护的主体包含两个条目的实现。条目Nums只能在gate为True时执行。条目Alpha只能在gate为false时执行。
声明了两个任务。
任务printnums循环遍历值1到26。在每个循环迭代中,该任务调用traffic_cop。nums然后打印数值。
任务printalpha循环遍历值“A”到“Z”。在每个循环迭代中,该任务调用traffic_cop。alpha然后打印alpha值。
当达到主过程的“开始”语句时,这两个任务都会自动启动。主过程不做任何事情,这由“null”命令明确指示。
该程序的输出为:
1A2B3C4D5E6F7G8H9I10J11K12L13M14N15O16P17Q18R19S20T212V23W24X25Y26Z
两个线程都在忙等待。所以这是可能的:
x
在NumThred中,再次检查x之后的NumPrted。
我试图实现这一点:第一个线程打印1,第二个线程打印2,第三个线程打印3,第一个线程打印4等等: 我做到了这一点,并发挥了作用: 输出是这样的: 它达到了目的,但是如果我有两个线程要打印,那么我必须使用更多的如果条件。 任何人都可以建议以更好的形式编写这段代码,以更干净的方式完成任务,这样如果添加更多线程,它就可以扩展。
我有一个类似的问题,但是我知道当我要求阅读一行时,发件人应该发送一个行尾。 让我困惑的是,在调试中,它是有效的。可能是因为我在调试时跳过的顺序(直到现在我都不知道这会有什么不同),但我想更好地理解它。 我已经使用线程,但不是很多。 这是我的服务器类: 线程(基于此) 和客户: 它似乎在某个地方进入了死锁,出于某种原因,除非在调试中运行,否则永远不要在向客户端发送数据的服务器类上输入该死锁 (顺便说
我想采取两个字符串和交替的字符到一个新的字符串使用for方法。 例如:“两个”和“一个” 结果:“townoe” 这就是我到目前为止所拥有的,我真的不知道如何完成它。
问题内容: 我在Python中有一个字符串 我试图替换以该词作为参数的函数输出开头的每个词。 有聪明的方法吗? 问题答案: 您可以将函数传递给。该函数将接收一个match对象作为参数,用于将匹配提取为字符串。
主要内容:字符串的输出,字符串的输入其实在《 C语言输入输出》一章中我们已经提到了如何输入输出字符串,但是那个时候我们还没有讲解字符串,大家理解的可能不透彻,所以本节我们有必要再深入和细化一下。 字符串的输出 在C语言中,有两个函数可以在控制台(显示器)上输出字符串,它们分别是: puts():输出字符串并自动换行,该函数只能输出字符串。 printf():通过格式控制符输出字符串,不能自动换行。除了字符串,printf() 还能输
问题内容: 我一直在尝试解决涉及使用wait()和notify()的线程通信的问题。基本上我有2个线程T1和T2,我希望它们按以下顺序执行 T1,T2,T1,T2 .....我该如何实现? 实际的问题:有两个线程T1-打印奇数(例如1-100),而T2-打印偶数(1-100)。现在,输出应为1,2,3,4,5,.... 100 问题答案: 您描述了生产者-消费者模式。 它是Java的实现,在许多J