多线程的交替打印问题(如两个线程循环打印1到100、三个线程循环打印a到z等都可以使用CountDownLatch解决),这里记录我使用CountDownLatch遇到的一个bug。
先看使用两个线程交替打印1-100
public class PrintaToz {
static int i = 0;
public static void main(String[] args) {
test();
}
static void test(){
CountDownLatch c1 = new CountDownLatch(2);
Thread t1 = new Thread(() -> {
int count = 26;
while (i < count){
// if(i % 2 == 0 && i < count){
if(i % 2 == 0){
char tar = (char) (i + 'a');
System.out.println(tar);
i++;
}
}
c1.countDown();
},"t1");
Thread t2 = new Thread(() -> {
int count = 26;
while (i < count){
// if(i % 2 == 1 && i < count){
if(i % 2 == 1){
char tar = (char) (i + 'a');
System.out.println(tar);
i++;
}
}
c1.countDown();
},"t2");
t1.start();
t2.start();
try {
c1.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
多执行几次,反复观察程序输出,会发现有时会输出27个字符,多输出了ASCII中字符z
的后一位{
a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
q
r
s
t
u
v
w
x
y
z
{
为什么呢?
考虑当i = 25
时,第一个线程判断i < count
不成立,进入内部的if
判断,但如果进入if
前第二个线程将i
改为了26,那么判断成立,因此会多输出一个字符。
如何解决呢,我的解决方法是在if
内再判断一次while
中的条件,是否有更好的方案呢,期待你的答案。
顺便提一下,这里两个线程同时操作变量i
却没有线程安全问题,这是因为两个线程操作i
的时间是错开的,因此是线程安全的。
此外,改方法可以简单改动实现变种的交替打印问题,如三个线程分别打印A B循环100次可以采用下面方式实现。
public class PrintABC {
public static void main(String[] args) {
printAB();
}
/**
* 两个线程循环打印A,B 100次
*/
static int i = 0;
static void printAB(){
CountDownLatch c = new CountDownLatch(2);
Thread t1 = new Thread(() ->{
int total = 100*2;
while (i < total){
if(i % 2 == 0){
System.out.print(Thread.currentThread().getName()+" ");
System.out.println("A");
i++;
}
}
c.countDown();
},"t1");
Thread t2 = new Thread(() ->{
int total = 100*2;
while (i < total){
if(i % 2 == 1){
System.out.print(Thread.currentThread().getName()+" ");
System.out.println("B");
i++;
}
}
c.countDown();
},"t2");
t1.start();
t2.start();
try {
c.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}