如何讓兩個線程交替打印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; } } } } } } 複製代碼
這是最簡單最高效的實現方式,由於不須要加鎖。比前面兩種實現方式都要好一些。多線程