多執行緒案例
阿新 • • 發佈:2020-08-07
一、執行緒的交替列印問題
兩個執行緒交替列印字母和數字,其中執行緒1列印數字,執行緒2列印字母,列印形式如下:
12A34B56C......
方法一,使用ReentrantLock實現,程式如下:
public class ThreadTest02 { private static Lock lock = new ReentrantLock(); private static Condition conditionA = lock.newCondition(); private static Condition conditionB = lock.newCondition(); private static volatile boolean flag = true; public void printNum(int i) throws InterruptedException { lock.lock(); while (!flag){ conditionA.await(); } System.out.print(2 * i - 1); System.out.print(2 * i); flag = false; conditionB.signal(); lock.unlock(); } public void printChar(int i) throws InterruptedException { lock.lock(); while (flag){ conditionB.await(); } System.out.print(Character.toChars(i - 1 + 'A')); flag = true; conditionA.signal(); lock.unlock(); } public static void main(String[] args) { ThreadTest02 test02 = new ThreadTest02(); new Thread(new Runnable() { @Override public void run() { for (int i = 1; i < 27; i++) { try { test02.printNum(i); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); new Thread(new Runnable() { @Override public void run() { for (int i = 1; i < 27; i++) { try { test02.printChar(i); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } }
condition也是基於AQS實現的,內部維護了一個等待佇列,所有呼叫condition.await方法的執行緒會加入到等待佇列中,並且執行緒狀態轉換為等待狀態。當呼叫condition.await()方法後會使得當前獲取lock的執行緒進入到等待佇列,如果該執行緒能夠從await()方法返回的話一定是該執行緒獲取了與condition相關聯的lock。
方法二,使用synchronized關鍵字解決:
public class ThreadTest03 { private static Object object = new Object(); private static volatile boolean flag = true; public void printNum(int i) throws InterruptedException { synchronized (object){ if(!flag){ object.wait(); } System.out.print(i * 2 - 1); System.out.print(i * 2); flag = false; object.notify(); } } public void printChar(int i) throws InterruptedException { synchronized (object){ if(flag){ object.wait(); } System.out.print(Character.toChars(i - 1 + 'A')); flag = true; object.notify(); } } public static void main(String[] args) { ThreadTest03 test03 = new ThreadTest03(); new Thread(new Runnable() { @Override public void run() { for (int i = 1; i < 27; i++) { try { test03.printNum(i); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); new Thread(new Runnable() { @Override public void run() { for (int i = 1; i < 27; i++) { try { test03.printChar(i); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } }
二、生產者和消費者問題
生產者-消費者問題,實際上是指程式中包含兩類執行緒,一種是用於生產資料的生產者執行緒,另一種是用於消費資料的消費者執行緒,生產者生產的資料放置於一個有固定容量的緩衝區當中,消費者從這個緩衝區中拿出資料消費。主要解決兩個問題:
- 如果共享資料區已滿的話,阻塞生產者繼續生產資料放置入內;
- 如果共享資料區為空的話,阻塞消費者繼續消費資料;
程式碼如下:
package com.practice.threadDemo; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class PSThreadTest04 { private static Lock lock = new ReentrantLock(); private static Condition conditionA = lock.newCondition(); private static Condition conditionB = lock.newCondition(); private static volatile int free_size = 10; //緩衝區可以容納的大小 public static void main(String[] args) { PSThreadTest04 test04 = new PSThreadTest04(); for (int k = 0; k < 5; k++) { new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 3; i++) { try { test04.new Producer().produce(); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } for (int k = 0; k < 5; k++) { new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 3; i++) { try { test04.new Consumer().consume(); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } } /**方法一 :ReentrantLock的方式實現 **/ class Producer { public void produce() throws InterruptedException { lock.lock(); while (free_size <= 0) { conditionA.await(); } System.out.println("生產者生產了一件產品"); free_size--; conditionB.signal(); lock.unlock(); } } class Consumer { public void consume() throws InterruptedException { lock.lock(); while (free_size == 10) { conditionB.await(); } System.out.println("消費者消費了一件產品"); free_size++; conditionA.signal(); lock.unlock(); } } }
此處也提供了第二種方法去實現:
package com.practice.threadDemo; public class PSThreadTest04 { private static volatile int free_size = 10; //緩衝區可以容納的大小 private static volatile Object object = new Object(); public static void main(String[] args) { PSThreadTest04 test04 = new PSThreadTest04(); for (int k = 0; k < 5; k++) { new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 3; i++) { try { test04.new Producer().produce(); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } for (int k = 0; k < 5; k++) { new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 3; i++) { try { test04.new Consumer().consume(); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } } /**方法二 :synchronized的方式實現 **/ class Producer{ public void produce() throws InterruptedException { synchronized (object){ while(free_size <= 0){ object.wait(); } System.out.println("生產者生產了一件產品"); free_size--; object.notify(); } } } class Consumer{ public void consume() throws InterruptedException { synchronized (object){ while(free_size >= 10){ object.wait(); } System.out.println("消費者消費了一件產品"); free_size++; object.notify(); } } } }