實現兩條執行緒交替列印奇偶數的兩種簡單方法
阿新 • • 發佈:2020-07-13
實現兩條執行緒交替列印奇偶數的兩種簡單方法
使用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(); } } }
此方法容易擴充套件到多條執行緒交替,且為精準喚醒,減少執行緒競爭帶來的消耗