競爭條件
1.競爭條件:
在java多線程中,當兩個或以上的線程對同一個數據進行操作的時候,可能會產生“競爭條件”的現象。這種現象產生的根本原因是因為多個線程在對同一個數據進行操作,此時對該數據的操作是非“原子化”的,可能前一個線程對數據的操作還沒有結束,后一個線程又開始對同樣的數據開始進行操作,這就可能會造成數據結果的變化未知。
package com.huojg.test; public class TestThread { public static void main(String[] args) { // new 出一個新的對象 t MyThread t = new MyThread(); /** * 兩個線程是在對同一個對象進行操作 */ Thread ta = new Thread(t, "Thread-A"); Thread tb = new Thread(t, "Thread-B"); ta.start(); tb.start(); } } class MyThread implements Runnable { // 變量 a 被兩個線程共同操作,可能會造成線程競爭 int a = 10; @Override public void run() { for (int i = 0; i < 5; i++) { a -= 1; try { Thread.sleep(1); } catch (InterruptedException e) {} System.out.println(Thread.currentThread().getName() + " → a = " + a); } } }
結果顯示:
Thread-A → a = 8 Thread-B → a = 8 Thread-A → a = 6 Thread-B → a = 6 Thread-B → a = 4 Thread-A → a = 4 Thread-B → a = 2 Thread-A → a = 2 Thread-A → a = 0 Thread-B → a = 0
從上面的結果中我們可以看到,在線程A對數據進行了操作之后,他還沒有來得及數據進行下一次的操作,此時線程B也對數據進行了操作,導致數據a一次性被減了兩次,以至於a為9的時候的值根本沒有打印出來,a為0的時候卻被打印了兩次。
那么,我們要如何才能避免結果這種情況的出現呢?
2.線程鎖
如果在一個線程對數據進行操作的時候,禁止另外一個線程操作此數據,那么,就能很好的解決以上的問題了。這種操作叫做給線程加鎖。
package com.huojg.test; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * 在Java多線程中,當兩個或以上的線程對同一個數據進行操作的時候,可能會產生“競爭條件”的現象。這種現象產生的根本原因是因為多個線程在對同一個數據進行操作,此時對該數據的操作是非“原子化”的, * 可能前一個線程對數據的操作還沒有結束,后一個線程又開始對同樣的數據開始進行操作,這就可能會造成數據結果的變化未知。 * * * 2.線程鎖 如果在一個線程對數據進行操作的時候,禁止另外一個線程操作此數據,那么,就能很好的解決以上的問題了。這種操作叫做給線程加鎖。 * */ public class TestThread { public static void main(String[] args) { // new 出一個新的對象 t MyThread t = new MyThread(); /** * 兩個線程是在對同一個對象進行操作 */ Thread ta = new Thread(t, "Thread-A"); Thread tb = new Thread(t, "Thread-B"); ta.start(); tb.start(); } } class MyThread implements Runnable { // 聲明鎖 private Lock lock = new ReentrantLock(); // 變量 a 被兩個線程共同操作,可能會造成線程競爭 int a = 10; @Override public void run() { // 加鎖 lock.lock(); for (int i = 0; i < 5; i++) { a -= 1; try { Thread.sleep(1); } catch (InterruptedException e) {} System.out.println(Thread.currentThread().getName() + " → a = " + a); } lock.unlock(); } }
運行結果:
Thread-A → a = 9 Thread-A → a = 8 Thread-A → a = 7 Thread-A → a = 6 Thread-A → a = 5 Thread-B → a = 4 Thread-B → a = 3 Thread-B → a = 2 Thread-B → a = 1 Thread-B → a = 0
上面的代碼給出了給線程枷鎖的方式,可以看到,在線程對數據進行操作之前先給此操作加一把鎖,那么在此線程對數據進行操作的時候,其他的線程無法對此數據進行操作,只能“阻塞”在一邊等待當前線程對數據操作結束后再對數據進行下一次的操作,當前線程在數據的操作完成之后會解開當前的鎖以便下一個線程操作此數據
用synchronized關鍵字加鎖來對方法進行加鎖:結果一樣;
總結:
Java中的多線程,當多個線程對一個數據進行操作時,可能會產生“競爭條件”的現象,這時候需要對線程的操作進行加鎖,來解決多線程操作一個數據時可能產生問題。加鎖方式有兩種,一個是申明Lock對象來對語句快進行加鎖,另一種是通過synchronized 關鍵字來對方法進行加鎖。以上兩種方法都可以有效解決Java多線程中存在的競爭條件的問題。