問題:
已知字符串abcdefghijk, 有兩個線程同時操作,實現一下一次循環遍歷出123456789。
例如:t1線程結果是1、 t2線程結果是2、 再是t1 = 3這樣的.、、、
本人使用ReentrantLock及Condition實現思路如下,歡迎多指點交流:
PS:show me code:
package com.lpz.test.interview;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* 有字符串123456789這樣的, 有兩個線程同時執行,實現一下一次循環遍歷出123456789 例如:t1線程結果是1 t2線程結果是2 再是t1 = 3這樣的.
*
* @Author: lpz
* @Date: 2019-04-25 16:48
*/
public class TwoThread {
final static String str = "abcdefghijk";
volatile AtomicInteger flag = new AtomicInteger(0);
ReentrantLock lock = new ReentrantLock();
Condition oddCondi = lock.newCondition();
Condition evenCondi = lock.newCondition();
public static void main(String[] args) {
List<String> list = new ArrayList<>();
for (int i = 0; i < str.length(); i++) {
list.add(str.substring(i, i + 1));
}
System.out.println(list + " size: " + list.size());
TwoThread twoThread = new TwoThread();
for (int i = 0, num = list.size(); i <= num/2; i++) {
// 偶數線程
new Thread(() -> {
twoThread.printEvenNum(list);
}, "even").start();
// 基數線程
new Thread(() -> {
twoThread.printOddNum(list);
}, "odd").start();
}
}
/**
* 打印奇數odd
*/
public void printOddNum(List<String> list) {
try {
lock.lockInterruptibly();
while (flag.get() == list.size()) {
return;
}
// 若偶數,奇數線程等待
while (flag.get() % 2 == 0) {
oddCondi.await();
}
//奇數來了,doing odd
// 偶爾報異常:Exception in thread "odd" java.lang.IndexOutOfBoundsException: Index: 11, Size: 11
// 但是上面有flag的return判斷啊。。。求解
System.out.println(Thread.currentThread().getName() + " --- " + flag + " --- " + list.get(flag.get()));
flag.incrementAndGet();
// 喚起偶數線程
evenCondi.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
/**
* 打印偶數even
*/
public void printEvenNum(List<String> list) {
try {
lock.lockInterruptibly();
// 使用while代替if,防止虛假喚醒?
while (flag.get() == list.size()) {
return;
}
// 奇數情況下,偶數等待
while (flag.get() % 2 == 1) {
evenCondi.await();
}
// 偶數來了,doing even
System.out.println(Thread.currentThread().getName() + " --- " + flag + " --- " + list.get(flag.get()));
flag.getAndIncrement();
// 喚起奇數線程
oddCondi.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
結果:
Connected to the target VM, address: '127.0.0.1:58542', transport: 'socket'
[a, b, c, d, e, f, g, h, i, j, k] size: 11
even --- 0 --- a
odd --- 1 --- b
even --- 2 --- c
odd --- 3 --- d
even --- 4 --- e
odd --- 5 --- f
even --- 6 --- g
odd --- 7 --- h
even --- 8 --- i
odd --- 9 --- j
even --- 10 --- k
Disconnected from the target VM, address: '127.0.0.1:58542', transport: 'socket'