如何让两个线程交替打印1-100的数字?废话很少说,直接上代码:java
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicInteger; public class StrangePrinter { private int max; private AtomicInteger status = new AtomicInteger(1); // AtomicInteger保证可见性,也能够用volatile public StrangePrinter(int max) { this.max = max; } public static void main(String[] args) { StrangePrinter strangePrinter = new StrangePrinter(100); ExecutorService executorService = Executors.newFixedThreadPool(2); executorService.submit(strangePrinter.new MyPrinter("Print1", 0)); executorService.submit(strangePrinter.new MyPrinter("Print2", 1)); executorService.shutdown(); } class MyPrinter implements Runnable { private String name; private int type; // 打印的类型,0:表明打印奇数,1:表明打印偶数 public MyPrinter(String name, int type) { this.name = name; this.type = type; } @Override public void run() { if (type == 1) { while (status.get() <= max) { synchronized (StrangePrinter.class) { // 加锁,保证下面的操做是一个原子操做 // 打印偶数 if (status.get() <= max && status.get() % 2 == 0) { // 打印偶数 System.out.println(name + " - " + status.getAndIncrement()); } } } } else { while (status.get() <= max) { synchronized (StrangePrinter.class) { // 加锁 // 打印奇数 if (status.get() <= max && status.get() % 2 != 0) { // 打印奇数 System.out.println(name + " - " + status.getAndIncrement()); } } } } } } } 复制代码
这里须要注意两点:bash
status.getAndIncrement()
后,此时status又是奇数了,当此时cpu将线程2挂起,调度线程1,就会出现线程2还没来得及打印偶数,线程1就已经打印了下一个奇数的状况。就不符合题目要求了。所以这里加锁是必须的,保证代码块中的是一个原子操做。import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicInteger; public class StrangePrinter2 { Object odd = new Object(); // 奇数条件锁 Object even = new Object(); // 偶数条件锁 private int max; private AtomicInteger status = new AtomicInteger(1); // AtomicInteger保证可见性,也能够用volatile public StrangePrinter2(int max) { this.max = max; } public static void main(String[] args) { StrangePrinter2 strangePrinter = new StrangePrinter2(100); ExecutorService executorService = Executors.newFixedThreadPool(2); executorService.submit(strangePrinter.new MyPrinter("偶数Printer", 0)); executorService.submit(strangePrinter.new MyPrinter("奇数Printer", 1)); executorService.shutdown(); } class MyPrinter implements Runnable { private String name; private int type; // 打印的类型,0:表明打印奇数,1:表明打印偶数 public MyPrinter(String name, int type) { this.name = name; this.type = type; } @Override public void run() { if (type == 1) { while (status.get() <= max) { // 打印奇数 if (status.get() % 2 == 0) { // 若是当前为偶数,则等待 synchronized (odd) { try { odd.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } else { System.out.println(name + " - " + status.getAndIncrement()); // 打印奇数 synchronized (even) { // 通知偶数打印线程 even.notify(); } } } } else { while (status.get() <= max) { // 打印偶数 if (status.get() % 2 != 0) { // 若是当前为奇数,则等待 synchronized (even) { try { even.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } else { System.out.println(name + " - " + status.getAndIncrement()); // 打印偶数 synchronized (odd) { // 通知奇数打印线程 odd.notify(); } } } } } } } 复制代码
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class StrangePrinter3 { private int max; private AtomicInteger status = new AtomicInteger(1); // AtomicInteger保证可见性,也能够用volatile private ReentrantLock lock = new ReentrantLock(); private Condition odd = lock.newCondition(); private Condition even = lock.newCondition(); public StrangePrinter3(int max) { this.max = max; } public static void main(String[] args) { StrangePrinter3 strangePrinter = new StrangePrinter3(100); ExecutorService executorService = Executors.newFixedThreadPool(2); executorService.submit(strangePrinter.new MyPrinter("偶数Printer", 0)); executorService.submit(strangePrinter.new MyPrinter("奇数Printer", 1)); executorService.shutdown(); } class MyPrinter implements Runnable { private String name; private int type; // 打印的类型,0:表明打印奇数,1:表明打印偶数 public MyPrinter(String name, int type) { this.name = name; this.type = type; } @Override public void run() { if (type == 1) { while (status.get() <= max) { // 打印奇数 lock.lock(); try { if (status.get() % 2 == 0) { odd.await(); } if (status.get() <= max) { System.out.println(name + " - " + status.getAndIncrement()); // 打印奇数 } even.signal(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } } else { while (status.get() <= max) { // 打印偶数 lock.lock(); try { if (status.get() % 2 != 0) { even.await(); } if (status.get() <= max) { System.out.println(name + " - " + status.getAndIncrement()); // 打印偶数 } odd.signal(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } } } } } 复制代码
这里的实现思路其实和使用Object的wait和notify机制差很少。markdown
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicInteger; public class StrangePrinter4 { private int max; private AtomicInteger status = new AtomicInteger(1); // AtomicInteger保证可见性,也能够用volatile private boolean oddFlag = true; public StrangePrinter4(int max) { this.max = max; } public static void main(String[] args) { StrangePrinter4 strangePrinter = new StrangePrinter4(100); ExecutorService executorService = Executors.newFixedThreadPool(2); executorService.submit(strangePrinter.new MyPrinter("偶数Printer", 0)); executorService.submit(strangePrinter.new MyPrinter("奇数Printer", 1)); executorService.shutdown(); } class MyPrinter implements Runnable { private String name; private int type; // 打印的类型,0:表明打印奇数,1:表明打印偶数 public MyPrinter(String name, int type) { this.name = name; this.type = type; } @Override public void run() { if (type == 1) { while (status.get() <= max) { // 打印奇数 if (oddFlag) { System.out.println(name + " - " + status.getAndIncrement()); // 打印奇数 oddFlag = !oddFlag; } } } else { while (status.get() <= max) { // 打印偶数 if (!oddFlag) { System.out.println(name + " - " + status.getAndIncrement()); // 打印奇数 oddFlag = !oddFlag; } } } } } } 复制代码
这是最简单最高效的实现方式,由于不须要加锁。比前面两种实现方式都要好一些。多线程