这世上有三样东西是别人抢不走的:一是吃进胃里的食物,二是藏在心中的梦想,三是读进大脑的书
- 分析题目。需要使用两个线程交替打印奇偶数。
-
-
- 定义两个信号量,一个奇数信号量,一个偶数信号量,都初始化为1
- 先用掉偶数的信号量,因为要让奇数先启动,等奇数打印完再释放
信号量实现
- 具体实现思路:
- 定义两个信号量,一个奇数信号量,一个偶数信号量,都初始化为1
- 先用掉偶数的信号量,因为要让奇数先启动,等奇数打印完再释放
- 具体流程就是 第一次的时候先减掉偶数的信号量 奇数线程打印完成以后用掉奇数的信号量。然后释放偶数的信号量如此循环
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
| import java.util.concurrent.Semaphore;
/** * @ClassName AlternatePrinting * @Author yunlogn * @Date 2019/5/21 * @Description 交替打印奇偶数 */ public class AlternatePrinting {
static int i = 0; public static void main(String[] args) throws InterruptedException {
Semaphore semaphoreOdd = new Semaphore(1); Semaphore semaphoreEven = new Semaphore(1);
semaphoreOdd.acquire(); //让奇数先等待启动,所以先减掉偶数的信号量 等奇数线程来释放
SemaphorePrintEven semaphorePrintEven = new SemaphorePrintEven(semaphoreOdd, semaphoreEven); Thread t1 = new Thread(semaphorePrintEven); t1.start();
SemaphorePrintOdd semaphorePrintOdd = new SemaphorePrintOdd(semaphoreOdd, semaphoreEven); Thread t2 = new Thread(semaphorePrintOdd); t2.start();
}
/** * 使用信号量实现 */ static class SemaphorePrintOdd implements Runnable {
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();//获取信号量 semaphoreOdd在初始化的时候被获取了信号量所以这里被阻塞了,所以会先执行下面的奇数线程 while (true) { i++; if (i % 2 == 0) { System.out.println("偶数线程:" + i); semaphoreEven.release();//释放偶数信号量 让奇数线程那边的阻塞解除 //再次申请获取偶数信号量,因为之前已经获取过,如果没有奇数线程去释放,那么就会一直阻塞在这,等待奇数线程释放 semaphoreOdd.acquire(); } } } catch (InterruptedException e) { e.printStackTrace(); } } }
static class SemaphorePrintEven implements Runnable {
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) {}
} } }
|
- 需要注意的是,如果某个线程来不及释放就异常中断了,会导致另一个线程一直在等,造成死锁。 虽然这个异常不在这个问题的考虑范围内 但是可以使用
finally
来包裹释放锁资源
同步锁打印
- 让两个线程使用同一把锁。交替执行 。
- 判断是不是奇数 如果是奇数进入奇数线程执行打印并加一。然后线程释放锁资源。然后让该线程等待
- 判断是不是偶数,如果是偶数进入偶数线程执行打印并加一。然后线程释放锁资源。然后让该线程等待
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
| import java.util.concurrent.atomic.AtomicInteger;
/** * @ClassName AlternatePrinting * @Author yunlogn * @Date 2019/5/21 * @Description 交替打印奇偶数 */ public class AlternatePrinting {
public static AtomicInteger atomicInteger = new AtomicInteger(1);
public static void main(String[] args) throws InterruptedException {
Thread a=new Thread(new AThread()); Thread b=new Thread(new BThread()); a.start(); b.start();
}
public static class AThread implements Runnable {
@Override public void run() { while (true) { synchronized (atomicInteger) { if (atomicInteger.intValue() % 2 != 0) { System.out.println("奇数线程:" + atomicInteger.intValue()); atomicInteger.getAndIncrement(); // 奇数线程释放锁资源 atomicInteger.notify(); try { atomicInteger.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } else { try { // 奇数线程等待 atomicInteger.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } } }
public static class BThread implements Runnable {
@Override public void run() { while (true){ synchronized (atomicInteger){ if(atomicInteger.intValue() %2== 0 ){ System.out.println("偶数线程:"+ atomicInteger.intValue()); atomicInteger.getAndIncrement(); // 偶数线程释放锁资源 atomicInteger.notify(); try { atomicInteger.wait(); } catch (InterruptedException e) { e.printStackTrace(); } }else{ try { // 偶数线程等待 atomicInteger.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } } }
}
|
一种更简单的写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| public class TheadTest { public static void main(String[] args) { PrintDigitThread print1 = new PrintDigitThread((i) -> i % 2 == 1, "thread1"); PrintDigitThread print2 = new PrintDigitThread((i) -> i % 2 == 0, "thread2"); print1.start(); print2.start(); } } class ShareData { public static final AtomicInteger atomicInt = new AtomicInteger(0); } class PrintDigitThread extends Thread { private Predicate<Integer> predicate; public PrintDigitThread(Predicate<Integer> predicate, String name) { this.predicate = predicate; this.setName(name); } @Override public void run() { int v = ShareData.atomicInt.get(); while (v < 100) { synchronized (ShareData.atomicInt) { v = ShareData.atomicInt.get(); if (predicate.test(v)) { System.out.println(Thread.currentThread().getName() + ":" + v); ShareData.atomicInt.incrementAndGet(); try { ShareData.atomicInt.notify(); } catch (Exception ex) { } } else { try { ShareData.atomicInt.wait(); } catch (Exception ex) { } } } } } }
|
欢迎关注 http://yunlongn.github.io