1. 線程安全問題–共享資源能使用問題
例如:
<<湄公河行動>>
100張票
淘票票CGV 美團 貓眼
三個銷售渠道,100張票是一個共享資源!!!
三個銷售渠道,可以認爲是三個銷售線程!!!
問題一:
100張票共享資源問題,選什麼來保存?
局部變量:
在方法內,如果run方法執行,存在,run方法當前執行完畢,銷燬。
每一個線程對象中都有run方法,無法滿足共享問題
成員變量:
每一個線程對象中,都有一個對應的成員變量,非共享資源。
靜態成員變量:
屬於類變量,所有的當前類對象,使用的靜態成員變量都是一個,而且一處修改,處處
受影響。【共享資源】
問題二:
資源衝突問題
線程之間會相互搶佔,而且搶佔頻率很快,有可能會導致一張票賣了三次,也就是資源衝突問題
2. 鎖
所以爲了解決這個問題,我們用鎖來解決
以下鎖的是方法,無論誰調用,怎麼調用都會鎖住
2.1 同步代碼塊
格式:
synchronized (/* 鎖對象 */) {
}
特徵:
1. synchronized 小括號裏面的對象是鎖對象,並且要求如果是多線程的情況下,鎖對象必須是同一個對象。也就是runnable接口實現類對象。
2. synchronized 大括號中的代碼塊就是需要進行同步的代碼,或者說是加鎖的代碼,大括號裏面的內容,有且只允許一個線程進入。
3. 同步代碼塊越短越好,在保證安全的情況下,提高性能
問題:
1. 目前鎖對象感覺很隨意,存在一定的隱患
2. 代碼層級關係很複雜,看着有點麻煩
這個方法比較隨意,一把鎖會鎖了多個線程,有隱患
2.2 同步方法
定義在線程類內
synchronized 作爲關鍵字來修飾方法,修飾的方法就是對應的同步方法
有且只允許一個線程進入,到底是誰來完成的加鎖操作?
-
靜態成員方法
鎖對象,是當前類對應的字節碼文件.class
就是類名.class -
非靜態成員方法
鎖對象就是當前類對象 this
選擇同步方法是否使用static修飾問題
-
如果非static修飾,要保證執行的線程對象有且只有一個,因爲鎖對象就是當前線程對象
-
如果是static修飾,鎖對象具有唯一性,多個線程使用的鎖是同一個鎖。類似於同步代碼塊。
2.3 Lock鎖
Java提供了一個對於線程安全問題,加鎖操作相對於同步代碼塊和同步方法更加廣泛的一種操作方式。
- 對象化操作。
創建Lock構造方法
Lock lock = new ReentrantLock();
多態思想,不理解就先記着這麼用。 - 方法化操作。
開鎖:
unlock();
加鎖:
lock();
代碼如下:
class SingleThread5 implements Runnable {
// 共享資源
private static int ticket = 100;
// 定義一個成員變量 這裏用到了多態的思想,如果不理解,就先記着這麼用。
static Lock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
// lock對象加鎖
lock.lock();
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "售出了" + ticket + "張票");
ticket -= 1;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
System.out.println(Thread.currentThread().getName() + "售罄!");
break;
}
// 解除鎖
lock.unlock();
}
}
}
public class Demo5 {
public static void main(String[] args) {
Thread thread1 = new Thread(new SingleThread5(), "淘票票");
Thread thread2 = new Thread(new SingleThread5(), "貓眼");
Thread thread3 = new Thread(new SingleThread5(), "美圖");
thread1.start();
thread2.start();
thread3.start();
}
}
2.4 三種加鎖方式的總結
-
一鎖一線程,一鎖多線程問題。
使用對應的鎖操作對應的線程,考慮靜態和非靜態問題。
同步方法和Lock鎖使用。
靜態是一鎖多目標,非靜態是一鎖一目標 -
涉及到同步問題時,要考慮好鎖對象的選擇問題
同步代碼塊,同步方法,Lock對象。
3. 守護線程
守護線程,也稱之爲後臺線程,如果當前主線程GG思密達,守護線程也就GG思密達。
守護線程一般用於:
1. 自動下載
2. 操作日誌
3. 操作監控
方法是通過線程對象
setDeamon(boolean flag);
true爲守護線程
false缺省屬性,正常線程