1.為什么要同步訪問數據?
當兩個或以上的線程需要共享對同一數據的存取,可能會發生共享數據的訛誤。
2.實現同步的方式
2.1 ReentrantLock類
School類:
class School{ private int stuNum; private Lock lock; private Condition condition; public School(int stuNum) { this.stuNum = stuNum; lock = new ReentrantLock(); condition = lock.newCondition(); } ......
其中 lock是鎖對象, condition 是條件對象,
用法:
public void stuNums1(){ lock.lock(); try{ while (stuNum < 20){ System.out.println(stuNum+" < 20,等待數量變為20"); condition.await(); } stuNum -= 5; System.out.println(Thread.currentThread().toString() + ":" + stuNum); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void stuNums2(){ lock.lock(); try{ stuNum += 1; System.out.println(Thread.currentThread().toString() + ":" + stuNum); if (stuNum >= 20){ System.out.println(stuNum + ">20了,開始喚醒等待集的線程"); condition.signalAll(); } } finally { lock.unlock(); } }
當條件對象調用await()方法時候,當前線程會進入等待集,處於阻塞狀態,直到其他線程在同一條件上調用signalAll()方法為止。
當一個線程調用await()方法時候,沒有辦法重新激活自身,寄希望於其他線程,如果沒有其他線程重新激活等待中的線程,將會導致死鎖。
在對象狀態有利於等待線程的方向改變時調用signalAll()方法,解除等待線程的阻塞。
2.2 synchronized關鍵字
在聲明方法時,加上這個關鍵字,對象鎖會保護整個方法。其效果等價於2.1中的方法。
在這里 wait() notufyAll() 分別等價於 await() signalAll()方法。