多線程安全和線程同步

問題

線程不安全問題

在多個線程使用同一個資源的時候,有可能存在一個資源被一個線程佔有,但一系列操做(原子操做:不可再分割的操做)並未執行完成,執行過程當中的資源被其餘線程拿去用了。java

同步

在一個線程執行原子操做時,其餘線程不能佔有資源安全

1.同步代碼塊

同步鎖在括號中,是線程共同享有的資源ide

@Override
public void run() {
        for (int i = 0; i < 50; i++) {
            String name = Thread.currentThread().getName();
            synchronized (this) {//同步鎖,線程共同享有的資源,這裏的this是指Apple對象
            if (num > 0) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(name + "吃了第" + num-- + "個蘋果");
            }
        }
    }
}

2.同步方法(不能同步run方法)

使用synchronized來修飾方法,對於非靜態方法,同步鎖是this;對於非靜態方法,同步鎖是當前方法所在類的字節碼對象 類名.class性能

@Override
public void run() {
    for (int i = 0; i < 50; i++) {
        test();
    }
}

private synchronized void test() {
    String name = Thread.currentThread().getName();
    if (num > 0) {
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(name + "吃了第" + num-- + "個蘋果");
    }
}

3.鎖機制

synchronized採用了自動加鎖和釋放鎖的機制,手動加鎖的方法更加透明,功能更增強大ui

package java_study;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class Apple3 implements Runnable {
    public int num = 50;
    //1.因爲 Lock 是一個接口,使用其實現類 ReentrantLock 得到一個鎖對象
    private final Lock lock = new ReentrantLock();
    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            eat();
        }
    }

    private void eat() {
        //2.在方法的開始加鎖嗎,須要使用try-finally保證釋放鎖的進行
        lock.lock();
        try {
            if (num > 0) {
                Thread.sleep(10);
                String name = Thread.currentThread().getName();
                System.out.println(name + "吃了第" + num-- + "個蘋果");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            //3.釋放鎖
            lock.unlock();
        }
    }

}

public class ClockDemo {
    public static void main(String[] args) {
        Apple3 a = new Apple3();
        new Thread(a, "A").start();
        new Thread(a, "B").start();
        new Thread(a, "C").start();
    }
}

!同步的優缺點:

  • 使用synchronized提升了線程安全性,下降了性能,儘可能減少做用域 如:StringBuffer類 ArrayList HashMap
  • 不適用synchronized提高了性能。下降了線程安全性 如:StringBuilder類 Vector Hashtable

!Sleep 對鎖的影響

  • Sleep 不會致使鎖丟失,會一直佔用資源直到從 sleep 喚醒
相關文章
相關標籤/搜索