java基礎 關於執行緒安全
A變數安全:多執行緒同時執行一段程式碼
B執行緒同步:一個執行緒還沒執行完,另一個執行緒又進來接著執行。
看個簡單的例子。
- public class ThreadSafe implements java.lang.Runnable {
- int num = 1;
- public void run() {
- for (int i = 0; i < 3; i++) {
- num = num + 1;
- try {
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println("num is value +==="+Thread.currentThread().getName()+"---------" + num);
- }
- }
- }
public class ThreadSafe implements java.lang.Runnable {
int num = 1;
public void run() {
for (int i = 0; i < 3; i++) {
num = num + 1;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("num is value +==="+Thread.currentThread().getName()+"---------" + num);
}
}
}
public class TestMan {
public static void main(String[] args) {
Runnable safe=new ThreadSafe();
Thread thread1=new Thread(safe,"thread1");
Thread thread2=new Thread(safe,"thread2");
thread1.start();
thread2.start();
}
}
執行結果
num is value +===thread2---------3
num is value +===thread1---------4
num is value +===thread2---------5
num is value +===thread1---------6
num is value +===thread1---------7
num is value +===thread2---------7
很明顯是錯誤的,應為兩個執行緒共享同一個變數。這裡就是變數的安全問題。
解決辦法:
1拋棄單例項,多執行緒的方式,用多例項,多執行緒的方式,這樣就和單執行緒是一個樣了,不會出錯,但是是最接近傳統的程式設計模式
2不要用類的例項變數,經可能把變數封裝到方法內部。
1類的解決辦法的程式碼。
- public class TestMan {
- public static void main(String[] args) {
- Runnable safe=new ThreadSafe();
- Runnable safe2=new ThreadSafe();
- Thread thread1=new Thread(safe,"thread1");
- Thread thread2=new Thread(safe2,"thread2");
- thread1.start();
- thread2.start();
- }
- }
public class TestMan {
public static void main(String[] args) {
Runnable safe=new ThreadSafe();
Runnable safe2=new ThreadSafe();
Thread thread1=new Thread(safe,"thread1");
Thread thread2=new Thread(safe2,"thread2");
thread1.start();
thread2.start();
}
}
執行結果
num is value +===thread1---------2
num is value +===thread2---------2
num is value +===thread1---------3
num is value +===thread2---------3
num is value +===thread1---------4
num is value +===thread2---------4
2類解決辦法的程式碼
- public class ThreadSafe implements java.lang.Runnable {
- public void run() {
- int num = 1;
- for (int i = 0; i < 3; i++) {
- num = num + 1;
- try {
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println("num is value +==="+Thread.currentThread().getName()+"---------" + num);
- }
- }
- }
public class ThreadSafe implements java.lang.Runnable {
public void run() {
int num = 1;
for (int i = 0; i < 3; i++) {
num = num + 1;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("num is value +==="+Thread.currentThread().getName()+"---------" + num);
}
}
}
- public class TestMan {
- public static void main(String[] args) {
- Runnable safe=new ThreadSafe();
- Thread thread1=new Thread(safe,"thread1");
- Thread thread2=new Thread(safe,"thread2");
- thread1.start();
- thread2.start();
- }
- }
public class TestMan {
public static void main(String[] args) {
Runnable safe=new ThreadSafe();
Thread thread1=new Thread(safe,"thread1");
Thread thread2=new Thread(safe,"thread2");
thread1.start();
thread2.start();
}
}
執行結果
num is value +===thread2---------2
num is value +===thread1---------2
num is value +===thread1---------3
num is value +===thread2---------3
num is value +===thread1---------4
num is value +===thread2---------4
這兩種辦法,比較推薦適用第二個辦法,就是把變數經可能的封裝到風發內部,這樣他們就是執行緒的私有變數了。另外,從jdk1.2後,推出了 threadlocal 物件,它作為執行緒的一個區域性變數,可以為每個執行緒建立一個副本,用來儲存每個執行緒的屬性,各是各的,互不干擾。單每個 threadlocal變數只能儲存一個變數,假如有多個變數要儲存,那麼就要寫多個threadlocal物件。
我們把程式碼改寫一下。
- public class ThreadSafe implements java.lang.Runnable {
- ThreadLocal<Integer> local=new ThreadLocal<Integer>();
- public void run() {
- for (int i = 0; i < 3; i++) {
- if(local.get()==null){
- local.set(new Integer(1));
- }
- int num=local.get().intValue();
- num=num+1;
- local.set(new Integer(num));
- try {
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println("num is value +==="+Thread.currentThread().getName()+"---------" + local.get().intValue());
- }
- }
- }
public class ThreadSafe implements java.lang.Runnable {
ThreadLocal<Integer> local=new ThreadLocal<Integer>();
public void run() {
for (int i = 0; i < 3; i++) {
if(local.get()==null){
local.set(new Integer(1));
}
int num=local.get().intValue();
num=num+1;
local.set(new Integer(num));
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("num is value +==="+Thread.currentThread().getName()+"---------" + local.get().intValue());
}
}
}
- public class TestMan {
- public static void main(String[] args) {
- Runnable safe=new ThreadSafe();
- Thread thread1=new Thread(safe,"thread1");
- Thread thread2=new Thread(safe,"thread2");
- thread1.start();
- thread2.start();
- }
- }
public class TestMan {
public static void main(String[] args) {
Runnable safe=new ThreadSafe();
Thread thread1=new Thread(safe,"thread1");
Thread thread2=new Thread(safe,"thread2");
thread1.start();
thread2.start();
}
}
執行結果
num is value +===thread2---------2
num is value +===thread1---------2
num is value +===thread1---------3
num is value +===thread2---------3
num is value +===thread1---------4
num is value +===thread2---------4
結果是一樣的,所以這裡變數安全有3個辦法可以解決。
然後在說說執行緒的同步的問題。我們看上面的執行結果。
num is value +===thread2---------2
num is value +===thread1---------2
num is value +===thread1---------3
num is value +===thread2---------3
num is value +===thread1---------4
num is value +===thread2---------4
就 可以看出他們不是執行緒同步的,是thread1和thread2在交替執行的。在有些情況下,要求一段程式碼在執行的過程中是一個不可分割的實體,就是原子的。就是說當已經有執行緒在執行這段程式碼的時候,其他的執行緒必須等待他執行完畢後才能竟來執行,這就是所謂的執行緒同步。
java通過同步鎖來執行執行緒的同步和等待,也就是說,要不間斷執行的程式碼需要放在synchronized關鍵字標識的程式碼塊中。可以用來修飾程式碼塊,也可以修飾方法。
- public class ThreadSafe implements java.lang.Runnable{
- public synchronized void run() {
- int num = 1;
- for (int i = 0; i < 3; i++) {
- num = num + 1;
- try {
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println("num is value +==="+Thread.currentThread().getName()+"---------" + num);
- }
- }
- }
public class ThreadSafe implements java.lang.Runnable{
public synchronized void run() {
int num = 1;
for (int i = 0; i < 3; i++) {
num = num + 1;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("num is value +==="+Thread.currentThread().getName()+"---------" + num);
}
}
}
- public class TestMan {
- public static void main(String[] args) {
- Runnable safe=new ThreadSafe();
- Thread thread1=new Thread(safe,"thread1");
- Thread thread2=new Thread(safe,"thread2");
- thread1.start();
- thread2.start();
- }
- }
public class TestMan {
public static void main(String[] args) {
Runnable safe=new ThreadSafe();
Thread thread1=new Thread(safe,"thread1");
Thread thread2=new Thread(safe,"thread2");
thread1.start();
thread2.start();
}
}
執行結果
um is value +===thread1---------2
num is value +===thread1---------3
num is value +===thread1---------4
num is value +===thread2---------2
num is value +===thread2---------3
num is value +===thread2---------4
可以看到thread1執行結束後thread2才開始執行的。程式碼還可以這麼寫
- public class ThreadSafe implements java.lang.Runnable {
- public void run() {
- int num = 1;
- synchronized (this) {
- for (int i = 0; i < 3; i++) {
- num = num + 1;
- try {
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println("num is value +==="
- + Thread.currentThread().getName() + "---------" + num);
- }
- }
- }
- }
public class ThreadSafe implements java.lang.Runnable {
public void run() {
int num = 1;
synchronized (this) {
for (int i = 0; i < 3; i++) {
num = num + 1;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("num is value +==="
+ Thread.currentThread().getName() + "---------" + num);
}
}
}
}
在啟用同步鎖機制以後,需要避免
1無線等待,,執行緒B等待執行緒A執行完畢,然後執行緒A確進入了死迴圈。
2迴圈等待:兩個執行緒相互呼叫,都要求要同步執行,這個時候就先會迴圈等待,我等你執行,你也在等我執行,這個時候就死鎖了相關文章
- Java 多執行緒基礎(四)執行緒安全Java執行緒
- Java基礎之執行緒安全Java執行緒
- Java 執行緒基礎Java執行緒
- Java執行緒池一:執行緒基礎Java執行緒
- java - 多執行緒基礎Java執行緒
- iOS開發基礎——執行緒安全(執行緒鎖)iOS執行緒
- Java 多執行緒基礎(八)執行緒讓步Java執行緒
- Java多執行緒-基礎篇Java執行緒
- Java 基礎(十四)執行緒——下Java執行緒
- Java 多執行緒基礎 - CyclicBarrierJava執行緒
- [Java基礎]虛擬執行緒Java執行緒
- java基礎:執行緒與程式;執行緒的分工,協作,互斥;volatile關鍵字Java執行緒
- Java基礎之執行緒那些事Java執行緒
- Java-基礎-執行緒入門Java執行緒
- JAVA_基礎多執行緒(一)Java執行緒
- Java 多執行緒基礎(六)執行緒等待與喚醒Java執行緒
- Java執行緒安全Java執行緒
- 執行緒基礎執行緒
- Java執行緒(一):執行緒安全與不安全Java執行緒
- 玩轉java多執行緒 之多執行緒基礎 執行緒狀態 及執行緒停止實戰Java執行緒
- Java 多執行緒基礎(十一)執行緒優先順序和守護執行緒Java執行緒
- 【Java多執行緒】執行緒安全的集合Java執行緒
- Java基礎之多執行緒程式設計Java執行緒程式設計
- JAVA多執行緒和併發基礎Java執行緒
- 【JAVA】【面試】【基礎篇】- 執行緒、鎖Java面試執行緒
- Java併發基礎(2)------執行緒池Java執行緒
- java基礎之執行緒 認識volatileJava執行緒
- java基礎-多執行緒初步瞭解Java執行緒
- 程式執行緒篇——程式執行緒基礎執行緒
- 最全java多執行緒學習總結1--執行緒基礎Java執行緒
- 多執行緒基礎執行緒
- 多執行緒系列(1),多執行緒基礎執行緒
- python基礎執行緒-管理併發執行緒Python執行緒
- 多執行緒系列(三):執行緒池基礎執行緒
- java基礎之執行緒 認識原子類Java執行緒
- (一)基礎篇:速讀Java執行緒池Java執行緒
- Java 執行緒基礎,從這篇開始Java執行緒
- Java併發程式設計-執行緒基礎Java程式設計執行緒