標籤:多線程 線上 關鍵字 str syn 其他 條件 列印 操作
競爭條件
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 = 8Thread-B → a = 8Thread-A → a = 6Thread-B → a = 6Thread-B → a = 4Thread-A → a = 4Thread-B → a = 2Thread-A → a = 2Thread-A → a = 0Thread-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 = 9Thread-A → a = 8Thread-A → a = 7Thread-A → a = 6Thread-A → a = 5Thread-B → a = 4Thread-B → a = 3Thread-B → a = 2Thread-B → a = 1Thread-B → a = 0
上面的代碼給出了給線程枷鎖的方式,可以看到,線上程對資料進行操作之前先給此操作加一把鎖,那麼在此線程對資料進行操作的時候,其他的線程無法對此資料進行操作,只能“阻塞”在一邊等待當前線程對資料操作結束後再對資料進行下一次的操作,當前線程在資料的操作完成之後會解開當前的鎖以便下一個線程操作此資料
用synchronized關鍵字加鎖來對方法進行加鎖:結果一樣;
總結:
Java中的多線程,當多個線程對一個資料進行操作時,可能會產生“競爭條件”的現象,這時候需要對線程的操作進行加鎖,來解決多線程操作一個資料時可能產生問題。加鎖方式有兩種,一個是申明Lock對象來對語句快進行加鎖,另一種是通過synchronized 關鍵字來對方法進行加鎖。以上兩種方法都可以有效解決Java多線程中存在的競爭條件的問題。
Java多線程中的競爭條件、鎖以及同步的概念