Java 在2个线程中交替输出数字和字母,不带锁
在一次采访中,我被要求使用两个而且只有两个线程来打印字符串Java 在2个线程中交替输出数字和字母,不带锁,java,multithreading,concurrency,Java,Multithreading,Concurrency,在一次采访中,我被要求使用两个而且只有两个线程来打印字符串1A2B3C…24X25Y26Z,其中一个线程只打印数字,另一个线程只打印字母。我编写了以下代码: 公共类应用程序{ 静态易失性int x=0; 静态易失性布尔numPrinted=false; 静态类NumThread实现Runnable{ @凌驾 公开募捐{ 而(x代码>它们自己的()堆栈,并通过单个共享的volatile boolean进行同步。这就是你的意思吗?@CedricSun这是一种方法。另一种方法是将计数器的范围扩大一倍,
1A2B3C…24X25Y26Z
,其中一个线程只打印数字,另一个线程只打印字母。我编写了以下代码:
公共类应用程序{
静态易失性int x=0;
静态易失性布尔numPrinted=false;
静态类NumThread实现Runnable{
@凌驾
公开募捐{
而(x<26){
如果(!numPrinted){
系统输出打印(x+1);
numPrinted=true;
}
}
}
}
静态类LetterThread实现可运行{
@凌驾
公开募捐{
而(x<26){
如果(numPrinted){
系统输出打印((字符)('A'+x));
++x;
numPrinted=false;
}
}
}
}
公共静态void main(字符串[]args){
Thread foo=新线程(new NumThread());
螺纹杆=新螺纹(新的LetterThread());
foo.start();
bar.start();
试一试{
foo.join();
bar.join();
}捕获(InterruptedException被忽略){
}
System.out.println();
}
}
在10次运行中,大约有1次将产生
1A2B3C4D5E6F7G8H9I10J11K12L13M14N15O16P17Q18R19S20T21U22V23W24X25Y26Z27
我的代码有什么并发性问题?我故意避免原子整数。两个线程都在忙着等待。所以这是可能的:
- 凸纹印花
- NumThread检查您的代码在两个类成员x和numPrinted上是否有竞争条件。
您可以尝试实现互斥和条件变量。
下面是一个每次都能正常工作的Ada示例
该示例使用一个受保护对象和两个任务。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;”命令显式指示 程序的输出为: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;
1A2B3C4D5E6F7G8H9I10J11K12L13M14N15O16P17Q18R19S20T21U2V23W24X25Y26Z仅使用一个共享变量(在本例中为
)就可以更容易地解决此问题。这表示哪个线程需要执行某些操作。线程本身可以跟踪其进度,等到需要打印某个内容时再打印,然后翻转对两个线程都可见的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; } } }
堆栈,并通过单个共享的static volatile boolean numPrinted=false; 静态类NumThread实现Runnable{ @凌驾 公开募捐{
对于(int=1;OOP数,我忘记了主线)…但是我们还是坚持下去。你想说“在NothToint”中吗?比如,<代码> >(NoMeNox&&席),改变逻辑只使用一个变量就简单了。@霍格尔,我可以看到每个线程如何依赖他们的内部计数器<代码> x>代码>它们自己的<代码>()
进行同步。这就是你的意思吗?@CedricSun这是一种方法。另一种方法是将计数器的范围扩大一倍,让一个线程等待偶数值,另一个线程等待奇数值(每个线程轮到它时前进一个,并使用计数器/2进行打印).任何一种方法都应该有效。volatile boolean