要求:使用多个线程轮流打印字符
- 方法1。无锁自旋,一般在多核机器并且临界区耗时很短的话可以尝试自旋
public class printABC {
static Logger log = new Logger(Logger.LogLevel.DEBUG, printABC.class);
static volatile int cur = 0;
public static void main(String[] args) {
String[] strings = {"A", "B", "C"};
int n = strings.length;
int printCnt = 100;
int cnt = n * printCnt;
for (int i = 0; i < n; i++) {
int j = i;
new Thread(() -> {
while (cur < cnt) {
if (cur % n == j && cur < cnt) {
log.info(cur / n + " - " + strings[j]);
cur++;
}
}
}).start();
}
}
}
- 方法2。使用
ReentrantLock
锁
public class printABC {
static Logger log = new Logger(Logger.LogLevel.DEBUG, printABC.class);
static volatile int cur = 0;
static final ReentrantLock lock = new ReentrantLock();
static Condition condition = lock.newCondition();
public static void main(String[] args) {
String[] strings = {"A", "B", "C"};
int n = strings.length;
int printCnt = 100;
int cnt = n * printCnt;
for (int i = 0; i < n; i++) {
int j = i;
new Thread(() -> {
while (cur < cnt) {
lock.lock();
try {
if (cur % n == j && cur < cnt) {
log.info(cur / n + " - " + strings[j]);
cur++;
condition.signalAll();
}else{
condition.await();
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
}
}).start();
}
}
}
- 方法3。使用
synchronized
锁
public class printABC {
static Logger log = new Logger(Logger.LogLevel.DEBUG, printABC.class);
static volatile int cur = 0;
static final ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
String[] strings = {"A", "B", "C"};
int n = strings.length;
int printCnt = 100;
int cnt = n * printCnt;
for (int i = 0; i < n; i++) {
int j = i;
new Thread(() -> {
while (cur < cnt) {
synchronized (lock) {
if (cur % n == j && cur < cnt) {
log.info(cur / n + " - " + strings[j]);
cur++;
lock.notifyAll();
} else {
try {
lock.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
}).start();
}
}
}
对于初学者来说需要注意的点:
- 如果使用加锁方式的话,在线程调用阻塞方法时需要先获取到锁,否则会抛异常
- 当线程被唤醒时需要注意虚假唤醒的情况
- 多线程共享变量
volatile
是一定要加的