java线程锁机制_多线程之锁机制
前言
在Java并發編程實戰,會經常遇到多個線程訪問同一個資源的情況,這個時候就需要維護數據的一致性,否則會出現各種數據錯誤,其中一種同步方式就是利用Synchronized關鍵字執行鎖機制,鎖機制是先給共享資源上鎖,只有拿到鎖的線程才可以訪問共享資源,其他線程進入等待狀態。下面將以實例代碼講解一下
一、wait()、nofity()、nofityAll()講解
示例代碼
package thread;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;/**
* Created by StoneGeek on 2018/5/19.
* 博客地址:http://www.cnblogs.com/sxkgeek* 當線程執行wait()時,會把當前的鎖釋放,然后讓出CPU,進入等待狀態。
* 當線程執行notify()/notifyAll()方法時,會喚醒一個處于等待狀態該對象鎖的線程,然后繼續往下執行,直到執行完退出對象鎖鎖住的區域(synchronized修飾的代碼塊)后再釋放鎖
* 個人認為synachronized(){}執行完后會釋放鎖*/
public classWaitNotify {static boolean flag = true;static Object lock = newObject();public static voidmain(String[] args) throws Exception {
Thread waitThread= new Thread(new Wait(), "WaitThread");
waitThread.start();
TimeUnit.SECONDS.sleep(1);
Thread notifyThread= new Thread(new Notify(), "NotifyThread");
notifyThread.start();
}static classWait implements Runnable {public voidrun() {//加鎖,擁有lock的Monitor
synchronized (lock) {//當條件不滿足時,繼續wait,同時釋放了lock的鎖
while(flag) {
System.out.println(Thread.currentThread().getName()+ "flag is true. wait@"
+ new SimpleDateFormat("HH:mm:ss")
.format(newDate()));try{lock.wait();
System.out.println("此處繼續執行"+Thread.currentThread().getName());//flag=true;
} catch(InterruptedException e) {
e.printStackTrace();
}
}//條件滿足時,完成工作
System.out.println(Thread.currentThread().getName()+ "flag is false. running@"
+ new SimpleDateFormat("HH:mm:ss").format(newDate()));
}
synchronized (lock){
System.out.println(Thread.currentThread().getName()+"執行結束");
}
}
}//wait()會立刻釋放synchronized(obj)中的obj鎖,以便其他線程可以執行obj.notify()//但是notify()不會立刻立刻釋放sycronized(obj)中的obj鎖,必須要等notify()所在線程執行完synchronized(obj)塊中的所有代碼才會釋放這把鎖.//yield(),sleep()不會釋放鎖
static classNotify implements Runnable {public voidrun() {//加鎖,擁有lock的Monitor
synchronized (lock) {//獲取lock的鎖,然后進行通知,通知時不會釋放lock的鎖,//直到當前線程釋放了lock后,WaitThread才能從wait方法中返回
System.out.println(Thread.currentThread().getName()+ "hold lock. notify @"
+ new SimpleDateFormat("HH:mm:ss").format(newDate()));lock.notifyAll();
flag= false;
}//再次加鎖
synchronized (lock) {
System.out.println(Thread.currentThread().getName()+ "hold lock again. sleep@"
+ new SimpleDateFormat("HH:mm:ss").format(newDate()));
}
synchronized (lock){
System.out.println(Thread.currentThread().getName()+"執行結束");
}
}
}
}
執行結果如下
1 WaitThread flag is true. wait@ 20:50:392 NotifyThread holdlock. notify @ 20:50:403 NotifyThread holdlock again. sleep@ 20:50:404 NotifyThread執行結束
5 此處繼續執行WaitThread
6 WaitThread flagis false. running@ 20:50:407 WaitThread執行結束
解釋:
首先創建一個lock對象,然后給這個lock上鎖來對多個進程同步,flag是一個標志,用來跳出while循環。
當線程執行wait()時,會把當前的鎖釋放,然后讓出CPU,進入等待狀態。
此時輪到notifythread線程,并且執行notifyAll(),這個意思是能夠喚醒所有正在等待這個lock對象的monitor的線程,但是
必須要等notify()所在線程執行完synchronized(obj)塊中的所有代碼才會釋放這把鎖,
此時接著waitthread被喚醒,繼續執行while循環,執行完之后,由于flag在notifythread中置為false,所以跳出while循環(如果在實例代碼的wail()后加flag=true結果是截然不同,由于notirythread進程執行完,此時會一直陷入wait,大家可以試試),
執行console打印5 6 7
notify()與notifyAll()的區別
notify()方法能夠喚醒一個正在等待該對象的monitor的線程,當有多個線程都在等待該對象
的monitor的話,則只能喚醒其中一個線程
而調用notifyAll()方法能夠喚醒所有正在等待這個對象的monitor的線程
當時的疑惑
(1)既然notify或者notifyAll需要執行完synchronized塊中的內容,那么他還有什么存在的價值的
后來執行完之后,才發現要是沒有這個方法,那么synchronized塊執行完之后,waitthread還是在等待狀態,無法被喚醒。
(2)wait被notify喚醒之后,是接著執行,所以console打印5,并不是從頭執行(如果在實例代碼的wail()后加flag=true結果是截然不同,由于notirythread進程執行完,waitthread進程重新執行wait方法,此時會一直陷入wait,無其他進程喚醒此進程)
二、sychronized(object)跟sychroized(this)的區別、使用場景
(1)首先創建一個objeck,然后sychronzied(object){}
static Object lock = newObject();
synchronized (lock) {}
這種情況是當多個線程執行不同的代碼但是希望分別執行,不同時進行,當然可以加wait、notify來進行鎖機制同步
(2)sychronized(this)
synchronized (lock) {}
這種情況是多個線程執行相同的代碼,但是希望分別執行.
三、wait()/wait(long)和sleep(long)方法的區別
將示例代碼中的lock.wait()改為Thread.sleep(1000),console打印
WaitThread flag is true. wait@ 21:29:49此處繼續執行WaitThread
WaitThread flagis true. wait@ 21:29:50此處繼續執行WaitThread
WaitThread flagis true. wait@ 21:29:51此處繼續執行WaitThread
WaitThread flagis true. wait@ 21:29:52此處繼續執行WaitThread
由此說明sleep并沒有釋放鎖。
區別:
1、Sleep(long)是Thread的方法,而wait()/wait(long)是Object的方法
2、Sleep(long)可以放在sychnoized塊內也可以不放在里面,但是wait()/wait(long)必須放在語句塊內
3、Sleep(long)不釋放鎖,只是讓當前線程暫停一段時間,而wait()/wait(long)是釋放鎖
4、wait()將當前線程放到阻塞隊列,只有調用notify()/notifyAll()方法后,才將其從阻塞隊列中移動到就緒隊列,等待被CPU調度,而wait(long)方法執行后就是放到阻塞隊列,等待時間到期或者被wait()/wait(long)喚醒后就可以放到就緒隊列被CPU調度
目前還有一個疑惑,就是線程中的run方法有兩個同樣的synchroized(lock),是不是跟一個synchroized(lock)效果是一樣的,目前就運行結果來看是這樣子的!
總結
以上是生活随笔為你收集整理的java线程锁机制_多线程之锁机制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java小数点的代码_java小数位的例
- 下一篇: mysql 存过 if_mysql中 储