在多個線程使用同一個資源的時候,有可能存在一個資源被一個線程佔有,但一系列操做(原子操做:不可再分割的操做)並未執行完成,執行過程當中的資源被其餘線程拿去用了。java
在一個線程執行原子操做時,其餘線程不能佔有資源安全
同步鎖在括號中,是線程共同享有的資源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-- + "個蘋果"); } } } }
使用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-- + "個蘋果"); } }
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(); } }