实现两条线程交替打印奇偶数的两种简单方法
使用Synchronized
public class Main {
private int count = 0;
public static void main(String[] args) throws InterruptedException {
Main main = new Main();
new Thread(()->{
for (int i = 0; i < 50; i++) {
try {
main.printEven();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 50; i++) {
try {
main.printOdd();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
}
//打印奇数方法
public synchronized void printOdd() throws InterruptedException {
while (this.count % 2 == 0) {//如果是偶数,则阻塞,释放锁
this.wait();
}
System.out.println(Thread.currentThread().getName() + this.count++);
this.notifyAll();//唤醒阻塞线程
}
//打印偶数方法
public synchronized void printEven() throws InterruptedException {
while (this.count % 2 != 0) {//如果是奇数,则阻塞,释放锁
this.wait();
}
System.out.println(Thread.currentThread().getName() + this.count++);
this.notifyAll();//唤醒阻塞线程
}
}
此方法不容易扩展到多条线程,越多的线程在唤醒时会经历越多的竞争,加大CPU资源浪费,同时也增加耗时
使用ReetrantLock+Condition实现精准唤醒
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class Turning {
public static void main(String[] args) throws InterruptedException {
Turning turning = new Turning();
new Thread(()->{
for (int i = 0; i < 50; i++) {
turning.printO();
}
},"A").start();
Thread.sleep(1000);
new Thread(()->{
for (int i = 0; i < 50; i++) {
turning.printJ();
}
},"B").start();
}
private ReentrantLock lock = new ReentrantLock();
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private int number = 0;
public void printJ() {
lock.lock();
try {
while (number % 2 == 0) {
condition1.await(); //如果是偶数,在此处阻塞
}
System.out.println(Thread.currentThread().getName()+number++);
condition2.signal(); //唤醒在2处阻塞的线程
}catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void printO() {
lock.lock();
try{
while (number % 2 != 0) {
condition2.await(); //如果是奇数,在此处阻塞
}
System.out.println(Thread.currentThread().getName()+number++);
condition1.signal(); //唤醒在1处阻塞的线程
}catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
此方法容易扩展到多条线程交替,且为精准唤醒,减少线程竞争带来的消耗