package com.lxh.Thread2; // 資源類 public class Resource { // 初始值 public int initValue = 0; }加1線程類:
package com.lxh.Thread2; // 加1操做 public class IncreaseThread implements Runnable { // 變量 public Resource res; // 構造方法 public IncreaseThread(Resource resource) { this.res = resource; } @Override public void run() { for(int i=0;i<5;i++){ synchronized (res) { this.res.initValue = res.initValue + 1; System.out.println(res+"***當前線程" + Thread.currentThread().getName() + ",加1以後initValue=" + res.initValue + "***"); } } } }減1線程類:
package com.lxh.Thread2; // 減1操做 public class ReduceThread implements Runnable { // 變量 public Resource res; // 構造方法 public ReduceThread(Resource resource) { this.res = resource; } @Override public void run() { for(int i=0;i<5;i++){ synchronized (res) { this.res.initValue = res.initValue - 1; System.out.println(res+"***當前線程" + Thread.currentThread().getName() + ",減1以後initValue=" + res.initValue + "***"); } } } }測試類:
package com.lxh.Thread2; public class Test { public static void main(String[] args) { Resource res = new Resource(); IncreaseThread it = new IncreaseThread(res); ReduceThread rt = new ReduceThread(res); Thread t1 = new Thread(it); Thread t2 = new Thread(it); Thread t3 = new Thread(rt); Thread t4 = new Thread(rt); t1.start(); t2.start(); t3.start(); t4.start(); } }3. 運行結果
小結: 這是一個簡單的"生產者----消費者"應用。 (爲何定一個資源類做爲參數傳遞? 由於這樣的話能夠保證initValue值在4個線程中共享,若是隻是定義一個int類型的變量則只能在相同的線程之間共享,好比同增或同減,不能在不一樣線程之間共享,好比加1線程和減1線程之間進行共享。) java
4. 若是在測試類中設置線程優先級,相關程序以下: 安全
package com.lxh.Thread2; // 加1操做 public class IncreaseThread implements Runnable { // 變量 public Resource res; // 構造方法 public IncreaseThread(Resource resource) { this.res = resource; } @Override public void run() { for(int i=0;i<20;i++){ synchronized (res) { this.res.initValue = res.initValue + 1; System.out.println(res+"***當前線程" + Thread.currentThread().getName() + ",加1以後initValue=" + res.initValue + "***"); } } } }
package com.lxh.Thread2; // 減1操做 public class ReduceThread implements Runnable { // 變量 public Resource res; // 構造方法 public ReduceThread(Resource resource) { this.res = resource; } @Override public void run() { for(int i=0;i<15;i++){ synchronized (res) { this.res.initValue = res.initValue - 1; System.out.println(res+"***當前線程" + Thread.currentThread().getName() + ",減1以後initValue=" + res.initValue + "***"); } } } }
package com.lxh.Thread2; public class Test { public static void main(String[] args) { Resource res = new Resource(); IncreaseThread it = new IncreaseThread(res); ReduceThread rt = new ReduceThread(res); Thread t1 = new Thread(it); Thread t2 = new Thread(it); Thread t3 = new Thread(rt); Thread t4 = new Thread(rt); // 設置線程優先級 t1.setPriority(Thread.MIN_PRIORITY);// 優先級最低 t2.setPriority(Thread.MAX_PRIORITY);// 優先級最高 t3.setPriority(3); t4.setPriority(7); t1.start(); t2.start(); t3.start(); t4.start(); } }運行結果:
小結:線程的優先級是能夠調節的,最高級爲10(Thread.MAX_PRIORITY),最低級爲1(Thread.MIN_PRIORITY),默認爲Thread.NORM_PRIORITY,越大得到CPU資源的能力就越強,特別說明:線程執行的次數多的時候該規律才明顯。 多線程
5. 爲何須要加synchronized關鍵字?代碼說明 ide
package com.lxh.Thread2; // 減1操做 public class ReduceThread implements Runnable { // 變量 public Resource res; // 構造方法 public ReduceThread(Resource resource) { this.res = resource; } @Override public void run() { System.out.println(res.initValue); for(int i=0;i<15;i++){ this.res.initValue = res.initValue - 1; System.out.println(res+"***當前線程" + Thread.currentThread().getName() + ",減1以後initValue=" + res.initValue + "***"); } } }
package com.lxh.Thread2; public class Test { public static void main(String[] args) { Resource res = new Resource(); IncreaseThread it = new IncreaseThread(res); ReduceThread rt = new ReduceThread(res); Thread t3 = new Thread(rt); Thread t4 = new Thread(rt); t3.start(); t4.start(); } }運行結果:
產生錯誤緣由:
Thread-3線程先獲取CPU資源執行,輸出res.initValue值(初始爲0),剛執行到for循環裏面,線程Thread-2就奪取了CPU資源,此時Thread-3在(this.res.initValue=res.initValue-1)到處於閒置狀態(不能說是等待狀態wait---等待狀態須要喚醒notify),而後Thread-2就開始輸出res.initValue值,而後,進入for循環,執行this.res.initValue = res.initValue-1;此時res.initValue=-1,就在此刻,Thread-3從新奪回CPU資源,執行this.res.initValue=res.initValue-1;此時res.initValue=-2,輸出1這行代碼,這個時候,Thread-2又從新奪回CPU資源,執行2這行代碼。
這就很好揭示了多線程出現安全問題的緣由:多個線程在同時執行某多行代碼的時候,一個線程只執行了多行代碼的部分,其餘線程就參與進來執行,形成共享數據錯誤。解決方案就是:在共享代碼段加上synchronized關鍵字。 測試