简介
三个线程一个线程输出0, 一个线程输出奇数, 还有一个线程输出偶数, 下面的代码感觉逻辑挺乱的.
code
import java.util.Scanner;
import java.util.concurrent.Semaphore;
import java.util.function.IntConsumer;
public class Main {
public static void main(String[] args) {
final Scanner reader = new Scanner(System.in);
int n = reader.nextInt();
ZeroEvenOdd zeroEvenOdd = new ZeroEvenOdd(n);
new Thread(() -> {
try {
zeroEvenOdd.printZero(System.out::print);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
try {
zeroEvenOdd.printEven(System.out::print);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
try {
zeroEvenOdd.printOdd(System.out::print);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
class ZeroEvenOdd {
private int n;
volatile int t;
volatile boolean b;
volatile boolean c;
public ZeroEvenOdd(int n) {
this.n = n;
t = n;
b = false;
c = false;
}
// printNumber.accept(x) outputs "x", where x is an integer.
public void printZero(IntConsumer printNumber) throws InterruptedException {
while(n > 0) {
synchronized (this) {
if(b == false) {
if(t!=n && t!=(n+1)) // 为什么要这么写呢, 首先比如输入n=5那么, 输出奇数他会首先输出1个0, 所以屏蔽, 然后奇数线程会获得执行然后输出1,然后他又获得执行权输出0
System.out.print(0);
b = true;
}
}
}
}
public void printEven(IntConsumer printNumber) throws InterruptedException {
while(n > 0) {
synchronized (this){
if(b == true) {
if(n %2 ==0) {
System.out.print(t-n);
n--;
b = false;
}
}
}
}
}
public void printOdd(IntConsumer printNumber) throws InterruptedException {
while(n > 0) {
synchronized (this) {
if(b == true) {
if (n % 2 != 0) {
System.out.print(t - n); // 这里会输出第一个0
n--;
b = false;
}
}
}
}
}
}
TIPS
逻辑上应该使用信号量, 因为信号量的使用场景就是这样子的. 顺序对于资源的把控
class AlternatePrinting {
public static void main(String[] args) throws InterruptedException {
Semaphore semaphoreOld = new Semaphore(1);
Semaphore semaphoreEven = new Semaphore(1);
semaphoreOld.acquire();//让奇数先启动,所以先减掉偶数的信号量 等奇数线程来释放
SemaphorePrintEven semaphorePrintEven = new SemaphorePrintEven(semaphoreOld, semaphoreEven);
Thread t1 = new Thread(semaphorePrintEven);
t1.start();
SemaphorePrintOdd semaphorePrintOdd = new SemaphorePrintOdd(semaphoreOld, semaphoreEven);
Thread t2 = new Thread(semaphorePrintOdd);
t2.start();
}
/**
* 使用信号量实现
*/
static class SemaphorePrintOdd implements Runnable {
int i = 0;
private Semaphore semaphoreOdd;
private Semaphore semaphoreEven;
public SemaphorePrintOdd(Semaphore semaphoreOdd, Semaphore semaphoreEven) {
this.semaphoreOdd = semaphoreOdd;
this.semaphoreEven = semaphoreEven;
}
@Override
public void run() {
try {
semaphoreOdd.acquire();//获取信号量
while (true) {
i++;
if (i % 2 == 0) {
System.out.println("偶数线程:" + i);
semaphoreEven.release();
//再次申请获取偶数信号量,因为之前已经获取过,如果没有奇数线程去释放,那么就会一直阻塞在这,等待奇数线程释放
Thread.sleep(300);
semaphoreOdd.acquire();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class SemaphorePrintEven implements Runnable {
int i = 0;
private Semaphore semaphoreOdd;
private Semaphore semaphoreEven;
public SemaphorePrintEven(Semaphore semaphoreOdd, Semaphore semaphoreEven) {
this.semaphoreOdd = semaphoreOdd;
this.semaphoreEven = semaphoreEven;
}
@Override
public void run() {
try {
semaphoreEven.acquire();
while (true) {
i++;
if (i % 2 == 1) {
System.out.println("奇数线程:" + i);
semaphoreOdd.release();
semaphoreEven.acquire();//再次申请获取奇数信号量,需要等偶数线程执行完然后释放该信号量,不然阻塞
}
}
} catch (Exception ex) {}
}
}
}