1. 什麼叫線程安全? 多線程對共用資源進行寫的操作,受到其他線程的干擾,導致數據偶問題,這種現象叫做線程安全問題。 運行結果: 線程安全解決的辦法: 使用多線程之間同步synchronized或使用鎖(lock)。 為什麼使用線程同步或使用鎖能解決線程安全問題呢? 將可能發生線程安全的代碼,在同一 ...
1. 什麼叫線程安全?
多線程對共用資源進行寫的操作,受到其他線程的干擾,導致數據偶問題,這種現象叫做線程安全問題。
package com.cn.test.thread; public class TrainThread implements Runnable { /** * 兩個線程進行售票100張 */ private int trainTicket = 100; @Override public void run() { while (trainTicket > 0) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } // 進行售票 System.out.println(Thread.currentThread().getName() + "開始售票:" + (100 - trainTicket + 1) + "張"); trainTicket--; } } public static void main(String[] args) { TrainThread train = new TrainThread(); Thread t1 = new Thread(train,"視窗1"); Thread t2 = new Thread(train,"視窗2"); t1.start(); t2.start(); } }
運行結果:
視窗1開始售票:1張
視窗2開始售票:1張
視窗1開始售票:3張
視窗2開始售票:3張
視窗1開始售票:5張
視窗2開始售票:5張
視窗1開始售票:7張
視窗2開始售票:7張
視窗2開始售票:9張
視窗1開始售票:9張
視窗2開始售票:11張
視窗1開始售票:12張
視窗2開始售票:13張
視窗1開始售票:14張
視窗2開始售票:15張
視窗1開始售票:16張
視窗2開始售票:17張
視窗1開始售票:18張
視窗2開始售票:19張
視窗1開始售票:20張
視窗2開始售票:21張
視窗1開始售票:22張
視窗2開始售票:23張
視窗1開始售票:24張
視窗2開始售票:25張
視窗1開始售票:26張
視窗2開始售票:27張
視窗1開始售票:28張
視窗2開始售票:29張
視窗1開始售票:30張
視窗2開始售票:31張
視窗1開始售票:32張
視窗2開始售票:33張
視窗1開始售票:34張
視窗2開始售票:35張
視窗1開始售票:36張
視窗2開始售票:37張
視窗1開始售票:38張
視窗2開始售票:39張
視窗1開始售票:40張
視窗2開始售票:41張
視窗1開始售票:42張
視窗2開始售票:43張
視窗1開始售票:44張
視窗2開始售票:45張
視窗1開始售票:46張
視窗2開始售票:47張
視窗1開始售票:48張
視窗2開始售票:49張
視窗1開始售票:50張
視窗2開始售票:51張
視窗1開始售票:52張
視窗2開始售票:53張
視窗1開始售票:54張
視窗2開始售票:55張
視窗1開始售票:56張
視窗2開始售票:57張
視窗1開始售票:58張
視窗2開始售票:59張
視窗1開始售票:60張
視窗2開始售票:61張
視窗1開始售票:62張
視窗2開始售票:63張
視窗1開始售票:64張
視窗2開始售票:65張
視窗1開始售票:66張
視窗2開始售票:67張
視窗1開始售票:68張
視窗2開始售票:69張
視窗1開始售票:70張
視窗2開始售票:71張
視窗1開始售票:72張
視窗2開始售票:73張
視窗1開始售票:74張
視窗2開始售票:75張
視窗1開始售票:76張
視窗2開始售票:77張
視窗1開始售票:78張
視窗2開始售票:79張
視窗1開始售票:80張
視窗2開始售票:81張
視窗1開始售票:82張
視窗2開始售票:83張
視窗1開始售票:84張
視窗2開始售票:85張
視窗1開始售票:86張
視窗2開始售票:87張
視窗1開始售票:88張
視窗2開始售票:89張
視窗1開始售票:90張
視窗2開始售票:91張
視窗1開始售票:92張
視窗2開始售票:93張
視窗1開始售票:94張
視窗2開始售票:95張
視窗1開始售票:96張
視窗2開始售票:97張
視窗1開始售票:98張
視窗2開始售票:99張
視窗1開始售票:100張
視窗2開始售票:101張
線程安全解決的辦法:
使用多線程之間同步synchronized或使用鎖(lock)。
為什麼使用線程同步或使用鎖能解決線程安全問題呢?
將可能發生線程安全的代碼,在同一時刻只有一個線程對此進行操作,代碼執行完畢之後釋放鎖之後才讓其他線程併發執行,這樣就會解決線程安全的問題。
什麼是線程同步?
多個線程共用同一個資源,不會受到其他線程的干擾。
解決辦法1:
同步代碼塊。 將可能發生線程安全的代碼用同步代碼塊包裹起來。
synchronized(同一個數據) {
可能會發生線程衝突問題
}
同步代碼塊需要傳遞的對象(鎖對象):就是鎖住這個對象,表示這個對象正在為我服務,其他人不能用(非synchronized代碼塊、方法除外)。
while (trainTicket > 0) { try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (obj) { // 進行售票 if (trainTicket > 0) { System.out.println(Thread.currentThread().getName() + "開始售票:" + (100 - trainTicket + 1) + "張"); trainTicket--; } } }
解決辦法2:
同步函數,在發生線程安全的函數中加入sychnorized關鍵字。
靜態同步函數:
方法上加上static關鍵字,使用synchronized 關鍵字修飾 或者使用類.class文件。靜態的同步函數使用的鎖是 該函數所屬位元組碼文件對象可以用 getClass方法獲取,也可以用當前 類名.class 表示。
死鎖:
同步中嵌套同步,導致鎖無法釋放
package com.cn.test.thread; public class TestDeadThread implements Runnable { private boolean flag = true; private static int trainCount = 100; private Object mutex = new Object(); @Override public void run() { if (flag) { while(true) { synchronized (mutex) { sale(); } } } else { while (true) { sale(); } } } private synchronized void sale() { synchronized (mutex) { if (trainCount > 0) { try { Thread.sleep(40); } catch (Exception e) { } System.out.println(Thread.currentThread().getName() + ",出售 第" + (100 - trainCount + 1) + "張票."); trainCount--; } } } public static void main(String[] args) throws InterruptedException { TestDeadThread test1 = new TestDeadThread(); Thread t1 = new Thread(test1,"thread-1"); Thread t2 = new Thread(test1,"thread-2"); t1.start(); Thread.sleep(40); test1.flag = false; t2.start(); } }
運行結果:
thread-1,出售 第1張票. thread-1,出售 第2張票. thread-1,出售 第3張票. thread-1,出售 第4張票. thread-1,出售 第5張票. thread-1,出售 第6張票. thread-1,出售 第7張票. thread-1,出售 第8張票. thread-1,出售 第9張票. thread-1,出售 第10張票. thread-1,出售 第11張票. thread-1,出售 第12張票. thread-1,出售 第13張票. thread-1,出售 第14張票. thread-1,出售 第15張票. thread-1,出售 第16張票. thread-1,出售 第17張票. thread-1,出售 第18張票. thread-1,出售 第19張票. thread-1,出售 第20張票. thread-1,出售 第21張票. thread-1,出售 第22張票. thread-1,出售 第23張票. thread-1,出售 第24張票. thread-1,出售 第25張票.