① POS線程同步互斥鎖和讀寫鎖的區別和各自適用場景
線程同步的方式包括:互斥鎖、讀寫鎖、條件變數、信號量和令牌。
以java語言為例:
用synchronized關鍵字修飾同步方法。
同步有幾種實現方法分別是synchronized,wait與notify
wait():使一個線程處於等待狀態,並且釋放所持有的對象的lock。
sleep():使一個正在運行的線程處於睡眠狀態,是一個靜態方法,調用此方法要捕捉InterruptedException異常。
notify():喚醒一個處於等待狀態的線程,注意的是在調用此方法的時候,並不能確切的喚醒某一個等待狀態的線程,而是由JVM確定喚醒哪個線程,而且不是按優先順序。
Allnotity():喚醒所有處入等待狀態的線程,注意並不是給所有喚醒線程一個對象的鎖,而是讓它們競爭。
同步是多線程中的重要概念。同步的使用可以保證在多線程運行的環境中,程序不會產生設計之外的錯誤結果。同步的實現方式有兩種,同步方法和同步塊,這兩種方式都要用到synchronized關鍵字。
給一個方法增加synchronized修飾符之後就可以使它成為同步方法,這個方法可以是靜態方法和非靜態方法,但是不能是抽象類的抽象方法,也不能是介面中的介面方法。下面代碼是一個同步方法的示例:
public synchronized void aMethod() {
// do something
}
public static synchronized void anotherMethod() {
// do something
}
線程在執行同步方法時是具有排它性的。當任意一個線程進入到一個對象的任意一個同步方法時,這個對象的所有同步方法都被鎖定了,在此期間,其他任何線程都不能訪問這個對象的任意一個同步方法,直到這個線程執行完它所調用的同步方法並從中退出,從而導致它釋放了該對象的同步鎖之後。在一個對象被某個線程鎖定之後,其他線程是可以訪問這個對象的所有非同步方法的。
同步塊是通過鎖定一個指定的對象,來對同步塊中包含的代碼進行同步;而同步方法是對這個方法塊里的代碼進行同步,而這種情況下鎖定的對象就是同步方法所屬的主體對象自身。如果這個方法是靜態同步方法呢?那麼線程鎖定的就不是這個類的對象了,也不是這個類自身,而是這個類對應的java.lang.Class類型的對象。同步方法和同步塊之間的相互制約只限於同一個對象之間,所以靜態同步方法只受它所屬類的其它靜態同步方法的制約,而跟這個類的實例(對象)沒有關系。
② 線程同步互斥鎖和讀寫鎖的區別和各自適用場景
線程同步的方式包括:互斥鎖、讀寫鎖、條件變數、信號量和令牌。互斥鎖和讀寫鎖:提供對臨界資源的保護,當多線程試圖訪問臨界資源時,都必須通過獲取鎖的方式來訪問臨界資源。(臨界資源:是被多線程共享的資源)當讀寫線程獲取鎖的頻率差別不大時,一般採用互斥鎖,如果讀線程訪問臨界資源的頻率大於寫線程,這個時候採用讀寫鎖較為合適,讀寫鎖允許多個讀線程同時訪問臨界資源,讀寫線程必須互斥訪問臨界資源。讀寫鎖的實現採用了互斥鎖,所以在讀寫次數差不多的情況下採用讀寫鎖性能沒有直接採用互斥鎖來的高。
③ java中實現同步的兩種方式syschronized和lock的區別和聯系
Lock是java.util.concurrent.locks包下的介面,Lock實現提供了比使用方法和語句可獲得的更廣泛的鎖定操作,它能以更優雅的方式處理線程同步問題,我們拿Java線程(二)中的一個例子簡單的實現一下和sychronized一樣的效果,代碼如下:
[java]view plain
Thread-4准備讀取數據
Thread-3准備讀取數據
Thread-5准備讀取數據
Thread-5讀取18
Thread-4讀取18
Thread-3讀取18
Thread-2准備寫入數據
Thread-2寫入6
Thread-2准備寫入數據
Thread-2寫入10
Thread-1准備寫入數據
Thread-1寫入22
Thread-5准備讀取數據
從結果可以看出實現了我們的需求,這只是鎖的基本用法,鎖的機制還需要繼續深入學習。
本文來自:高爽|Coder,原文地址:http://blog.csdn.net/ghsau/article/details/7461369,轉載請註明。
在java中有兩種方式實現原子性操作(即同步操作):
1)使用同步關鍵字synchronized
2)使用lock鎖機制其中也包括相應的讀寫鎖
package com.xiaohao.test;
import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class Test {
public static void main(String[] args) {
final LockTest lock=new LockTest();
//輸出張三
new Thread(){
public void run(){
lock.test("張三張三張三張三張三張三張三張三張三張三");
}
}.start();
//輸出李四
new Thread(){
public void run(){
lock.test("李四李四李四李四李四李四李四李四李四李四");System.out.println
("
---------------------------------------------------------------");
}
}.start();
//---------------------------------------------------------------
//模擬寫入數據的
for (int i = 0; i < 3; i++) {
new Thread(){
public void run() {
for (int j = 0; j < 5; j++) {
// lock.set(new Random().nextInt(30));
lock.set2(new Random().nextInt(30));
}
}
}.start();
}
//模擬讀取數據的
for (int i = 0; i < 3; i++) {
new Thread(){
public void run() {
for (int j = 0; j < 5; j++) {
// lock.get();
lock.get2();
}
}
}.start();
}
}
}
class LockTest{
private Lock lock=new ReentrantLock(); //創建普通的鎖
private ReadWriteLock readWriteLock=new ReentrantReadWriteLock();//創建讀寫鎖
private int data;// 共享數據
//實現同步的方法一 使用同步關鍵字 synchronized
public synchronized void test(String name){
//下面的相關操作是一個原子性的操作
// lock.lock();// 得到鎖
try {
for(int i = 0; i < name.length(); i++) {
System.out.print(name.charAt(i));
}
} finally {
// lock.unlock();// 釋放鎖
}
}
//實現同步的方法二 使用lock鎖機制
public void test2(String name){
//下面的相關操作是一個原子性的操作
lock.lock();// 得到鎖
try {
for(int i = 0; i < name.length(); i++) {
System.out.print(name.charAt(i));
}
} finally {
lock.unlock();// 釋放鎖
}
}
//使用set方法模擬寫入數據
//使用 synchronized 實現了讀讀,寫寫,讀寫之間的互斥 ,但讀讀之間的互斥是沒有什麼必要的
public synchronized void set(int data){
System.out.println(Thread.currentThread().getName() + "准備寫入數據");
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.data = data;
System.out.println(Thread.currentThread().getName() + "寫入" + this.data);
}
//使用get方法模擬讀取數據
//使用 synchronized 實現了讀讀,寫寫,讀寫之間的互斥 ,但讀讀之間的互斥是沒有什麼必要的
public synchronized void get() {
System.out.println(Thread.currentThread().getName() + "准備讀取數據");
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "讀取" + this.data);
}
//使用set方法模擬寫入數據
//使用 讀寫鎖實現了寫寫,讀寫之間的互斥 ,但讀讀之間的互斥是沒有什麼必要的
public void set2(int data){
readWriteLock.writeLock().lock();//獲取寫入鎖
try{
System.out.println(Thread.currentThread().getName() + "准備寫入數據");
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.data = data;
System.out.println(Thread.currentThread().getName() + "寫入" + this.data);
}
finally{
readWriteLock.writeLock().unlock();
}
}
//使用get方法模擬讀取數據
//使用 讀寫鎖實現了寫寫,讀寫之間的互斥 ,但讀讀之間的互斥是沒有什麼必要的
public void get2() {
//獲取相應的讀鎖
readWriteLock.readLock().lock();
try{
System.out.println(Thread.currentThread().getName() + "准備讀取數據");
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "讀取" + this.data);
}
finally{
// 釋放相應的寫鎖
readWriteLock.readLock().unlock();
}
}
}
線程同步經典版:
package com.xiaohao.test;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class Test2{
public static void main(String[] args){
final LockTest2 lockTest=new LockTest2();
for(int i=0;i<3;i++) {
new Thread(){
public void run(){
try {
for (int j = 0; j < 3; j++) {
lockTest.setValue();
} } catch (InterruptedException e) {
// TODO Auto-generated catch block e.printStackTrace();
}
}
}.start();
}
for(int i=0;i<3;i++) {
new Thread(){
public void run(){
try {
for (int j = 0; j < 3; j++) {
lockTest.getValue();
}
} catch (InterruptedException e)
{ // TODO Auto-generated catch block e.printStackTrace(); }
}
}.start();
}
}
}
class LockTest2 {
int data=0;
ReentrantReadWriteLock lock= new ReentrantReadWriteLock();// 鎖對象
public void setValue() throws InterruptedException{
lock.writeLock().lock();
System.out.println("正在使用寫鎖......");
data=(int) (Math.random()*10);
System.out.println("正在寫入:"+data);
Thread.sleep(500);
System.out.println("寫鎖調用完畢---------------------------");
lock.writeLock().unlock(); }
public void getValue() throws InterruptedException{
lock.readLock().lock();
System.out.println("正在使用讀鎖...........................................");
System.out.println("正在讀入:"+data); Thread.sleep(500);
System.out.println("讀鎖調用完畢......");
lock.readLock().unlock();
}
}
**** 當一個線程進入了一個對象是的synchronized方法,那麼其它線程還能掉否調用此對象的其它方法?
這個問題需要分幾種情況進行討論。
1)查看其它方法是否使用了同步關鍵字(synchronized)修飾,如果沒有的話就可以調用相關的方法。
2)在當前synchronized方法中是否調用了wait方法,如果調用了,則對應的鎖已經釋放,可以訪問了。
3)如果其它方法也使用synchronized修飾,並且當前同步方法中沒有調用wait方法的話,這樣是不允許訪問的。
4)如果其它方法是靜態方法的話,由於靜態方法和對象是扯不上什麼關系,對於靜態同步方法而言,其對應的同步監視器為當前類的位元組碼
所以肯定可以訪問的了。
④ JAVA中線程在什麼時候需要同步和互斥
同步:上一段代碼沒的完成,下一段必須等到上一段代碼完成後才可以執行。如買票排隊
非同步:上一段代碼沒的完成,下一段不必等到上一段代碼完成就可以執行。如手機發送簡訊。
例如訪問同一個資源:
例如車站的售票系統,一定是多個線程同時運行售票的吧。
有編號為10000這張票,那麼線程thread1正在賣它的時候,其餘的線程就不能也賣這張票了。
另一個就是著名的生產者-消費者問題。類比一下,老爸掙錢,打到銀行卡里,兒子花錢。(假設卡里有錢的話就暫時不打錢)
對於老爸老說,如果要打錢,查看一下卡,如果有錢,就暫時不放,並通知兒子已經有錢;如果沒錢,當然就打錢了。
對於兒子來說,取錢時如果有錢就取,如果沒有就等待,並通知老爸沒錢了。
這就是同步了
如果數據將在線程間共享。例如正在寫的數據以後可能被另一個線程讀到,或者正在讀的數據可能已經被另一個線程寫過了,那麼這些數據就是共享數據,必須進行同步存取。
當應用程序在對象上調用了一個需要花費很長時間來執行的方法,並且不希望讓程序等待方法的返回時,就應該使用非同步編程,在很多情況下採用非同步途徑往往更有效率。
面試的話 你就這樣告訴他
線程的同步意味安全 譬如你取錢 你的執行語和我用的是相同對象 那你要在卡上扣除的錢數扣在我卡上了 怎麼辦
至於非同步 是JAVA的閃亮點 設想下你搜索時 並沒有提交 只打上關鍵字 就出現了很多提示 ,另外 非同步在 體育節目方面的應用 在網上 你可以宣稱 你的產品 可以讓顧客看到賽場的比賽時鍾 這就是用非同步實現的
簡單的說,同步就是防止多個線程訪問同一個對象,造成數據不安全。
比如:一個男生和一個女生是男女朋友的關系,那麼,另外的一個男生要想追到這個女生,就得先等前面這個男生和這個女生分手了以後才可以,兩個男生不能同時訪問這個女生,這就是同步;非同步就是,在一個家庭中,幾個兄弟姐妹可以同時擁有相同的父母,不需要等待,都可以同時擁有,同時訪問。
⑤ 如何在Java多線程編程中實現程序同與互斥
作為一個完全面向對象的語言,Java提供了類 Java.lang.Thread 來方便多線程編程,這個類提供了大量的方法來方便我們控制自己的各個線程,我們以後的討論都將圍繞這個類進行。
Thread 類最重要的方法是 run() ,它為Thread 類的方法 start() 所調用,提供我們的線程所要執行的代碼。為了指定我們自己的代碼,只需要覆蓋它!
方法一:繼承 Thread 類,覆蓋方法 run()
我們在創建的 Thread 類的子類中重寫 run() ,加入線程所要執行的代碼即可。
下面是一個例子:
public class MyThread extends Thread {
int count= 1, number;
public MyThread(int num) {
number = num;
System.out.println("創建線程 " + number);
}
public void run() {
while(true) {
System.out.println("線程 " + number + ":計數 " + count);
if(++count== 6) return;
}
}
public static void main(String args[]) {
for(int i = 0; i < 5; i++) new MyThread(i+1).start();
}
}
這種方法簡單明了,符合大家的習慣,但是,它也有一個很大的缺點,那就是如果我們的類已經從一個類繼承(如小程序必須繼承自 Applet 類),則無法再繼承 Thread 類,這時如果我們又不想建立一個新的類.
一種新的方法:不創建 Thread 類的子類,而是直接使用它,那麼我們只能將我們的方法作為參數傳遞給 Thread 類的實例,有點類似回調函數。但是 Java 沒有指針,我們只能傳遞一個包含這個方法的類的實例。那麼如何限制這個類必須包含這一方法呢?當然是使用介面!(雖然抽象類也可滿足,但是需要繼承,而我們之所以要採用這種新方法,不就是為了避免繼承帶來的限制嗎?)
Java 提供了介面 Java.lang.Runnable 來支持這種方法。
方法二:實現 Runnable 介面
Runnable 介面只有一個方法 run(),我們聲明自己的類實現 Runnable 介面並提供這一方法,將我們的線程代碼寫入其中,就完成了這一部分的任務。
但是 Runnable 介面並沒有任何對線程的支持,我們還必須創建 Thread 類的實例,這一點通過 Thread 類的構造函數
public Thread(Runnable target);
來實現。
下面是一個例子:
public class MyThread implements Runnable {
int count= 1, number;
public MyThread(int num) {
number = num;
System.out.println("創建線程 " + number);
}
public void run() {
while(true) {
System.out.println("線程 " + number + ":計數 " + count);
if(++count== 6) return;
}
}
public static void main(String args[])
{
for(int i = 0; i < 5; i++) new Thread(new MyThread(i+1)).start();
}
}
⑥ java線程中的同步鎖和互斥鎖有什麼區別
互斥是通過競爭對資源的獨占使用,彼此之間不需要知道對方的存在,執行順序是一個亂序。
同步是協調多個相互關聯線程合作完成任務,彼此之間知道對方存在,執行順序往往是有序的。
⑦ 自旋鎖和互斥鎖的區別 java中lock Syntronized區別
自旋鎖(Spin lock)
自旋鎖與互斥鎖有點類似,只是自旋鎖不會引起調用者睡眠,如果自旋鎖已經被別的執行單元保持,調用者就一直循環在那裡看是
否該自旋鎖的保持者已經釋放了鎖,"自旋"一詞就是因此而得名。其作用是為了解決某項資源的互斥使用。因為自旋鎖不會引起調用者睡眠,所以自旋鎖的效率遠
高於互斥鎖。雖然它的效率比互斥鎖高,但是它也有些不足之處:
1、自旋鎖一直佔用CPU,他在未獲得鎖的情況下,一直運行--自旋,所以佔用著CPU,如果不能在很短的時 間內獲得鎖,這無疑會使CPU效率降低。
2、在用自旋鎖時有可能造成死鎖,當遞歸調用時有可能造成死鎖,調用有些其他函數也可能造成死鎖,如 _to_user()、_from_user()、kmalloc()等。
因此我們要慎重使用自旋鎖,自旋鎖只有在內核可搶占式或SMP的情況下才真正需要,在單CPU且不可搶占式的內核下,自旋鎖的操作為空操作。自旋鎖適用於鎖使用者保持鎖時間比較短的情況下。
兩種鎖的加鎖原理
互斥鎖:線程會從sleep(加鎖)——>running(解鎖),過程中有上下文的切換,cpu的搶占,信號的發送等開銷。
自旋鎖:線程一直是running(加鎖——>解鎖),死循環檢測鎖的標志位,機制不復雜。
互斥鎖屬於sleep-waiting類型的鎖。例如在一個雙核的機器上有兩個線程(線程A和線程B),它們分別運行在Core0和
Core1上。假設線程A想要通過pthread_mutex_lock操作去得到一個臨界區的鎖,而此時這個鎖正被線程B所持有,那麼線程A就會被阻塞
(blocking),Core0 會在此時進行上下文切換(Context
Switch)將線程A置於等待隊列中,此時Core0就可以運行其他的任務(例如另一個線程C)而不必進行忙等待。而自旋鎖則不然,它屬於busy-waiting類型的鎖,如果線程A是使用pthread_spin_lock操作去請求鎖,那麼線程A就會一直在
Core0上進行忙等待並不停的進行鎖請求,直到得到這個鎖為止。
兩種鎖的區別
互斥鎖的起始原始開銷要高於自旋鎖,但是基本是一勞永逸,臨界區持鎖時間的大小並不會對互斥鎖的開銷造成影響,而自旋鎖是死循環檢測,加鎖全程消耗cpu,起始開銷雖然低於互斥鎖,但是隨著持鎖時間,加鎖的開銷是線性增長。
兩種鎖的應用
互斥鎖用於臨界區持鎖時間比較長的操作,比如下面這些情況都可以考慮
1 臨界區有IO操作
2 臨界區代碼復雜或者循環量大
3 臨界區競爭非常激烈
4 單核處理器
至於自旋鎖就主要用在臨界區持鎖時間非常短且CPU資源不緊張的情況下,自旋鎖一般用於多核的伺服器。
lock與Syntronized的區別
轉自自:
java並發之Lock與synchronized的區別
1)Lock是一個介面,而synchronized是Java中的關鍵字,synchronized是內置的語言實現;
2)synchronized在發生異常時,會自動釋放線程佔有的鎖,因此不會導致死鎖現象發生;而Lock在發生異常時,如果沒有主動通過unLock()去釋放鎖,則很可能造成死鎖現象,因此使用Lock時需要在finally塊中釋放鎖;
3)Lock可以讓等待鎖的線程響應中斷,而synchronized卻不行,使用synchronized時,等待的線程會一直等待下去,不能夠響應中斷;
4)通過Lock可以知道有沒有成功獲取鎖,而synchronized卻無法辦到。
5)Lock可以提高多個線程進行讀操作的效率。
在性能上來說,如果競爭資源不激烈,兩者的性能是差不多的,而當競爭資源非常激烈時(即有大量線程同時競爭),此時Lock的性能要遠遠優於synchronized。所以說,在具體使用時要根據適當情況選擇。
兩者在鎖的相關概念上區別:
1.可重入鎖
如果鎖具備可重入性,則稱作為可重入鎖。像synchronized和ReentrantLock都是可重入鎖,可重入性在我看來實際上表明了鎖的分配機制:基於線程的分配,而不是基於方法調用的分配。舉個簡單的例子,當一個線程執行到某個synchronized方法時,比如說method1,而在method1中會調用另外一個synchronized方法method2,此時線程不必重新去申請鎖,而是可以直接執行方法method2。
看下面這段代碼就明白了:
1
2
3
4
5
6
7
8
9
class MyClass
{
public synchronized void method1()
{
method2();
}
public synchronized void method2()
{
}
}
上述代碼中的兩個方法method1和method2都用synchronized修飾了,假如某一時刻,線程A執行到了method1,此時線程A獲取了這個對象的鎖,而由於method2也是synchronized方法,假如synchronized不具備可重入性,此時線程A需要重新申請鎖。但是這就會造成一個問題,因為線程A已經持有了該對象的鎖,而又在申請獲取該對象的鎖,這樣就會線程A一直等待永遠不會獲取到的鎖。
而由於synchronized和Lock都具備可重入性,所以不會發生上述現象。
2.可中斷鎖
可中斷鎖:顧名思義,就是可以相應中斷的鎖。
在Java中,synchronized就不是可中斷鎖,而Lock是可中斷鎖。
如果某一線程A正在執行鎖中的代碼,另一線程B正在等待獲取該鎖,可能由於等待時間過長,線程B不想等待了,想先處理其他事情,我們可以讓它中斷自己或者在別的線程中中斷它,這種就是可中斷鎖。
在前面演示lockInterruptibly()的用法時已經體現了Lock的可中斷性。
3.公平鎖
公平鎖即盡量以請求鎖的順序來獲取鎖。比如同是有多個線程在等待一個鎖,當這個鎖被釋放時,等待時間最久的線程(最先請求的線程)會獲得該所,這種就是公平鎖。
非公平鎖即無法保證鎖的獲取是按照請求鎖的順序進行的。這樣就可能導致某個或者一些線程永遠獲取不到鎖。
在Java中,synchronized就是非公平鎖,它無法保證等待的線程獲取鎖的順序。
而對於ReentrantLock和ReentrantReadWriteLock,它默認情況下是非公平鎖,但是可以設置為公平鎖。
看一下這2個類的源代碼就清楚了:
在ReentrantLock中定義了2個靜態內部類,一個是NotFairSync,一個是FairSync,分別用來實現非公平鎖和公平鎖。
我們可以在創建ReentrantLock對象時,通過以下方式來設置鎖的公平性:
1
ReentrantLock
lock = new ReentrantLock(true);
如果參數為true表示為公平鎖,為fasle為非公平鎖。默認情況下,如果使用無參構造器,則是非公平鎖。
另外在ReentrantLock類中定義了很多方法,比如:
isFair() //判斷鎖是否是公平鎖
isLocked() //判斷鎖是否被任何線程獲取了
isHeldByCurrentThread() //判斷鎖是否被當前線程獲取了
hasQueuedThreads() //判斷是否有線程在等待該鎖
在ReentrantReadWriteLock中也有類似的方法,同樣也可以設置為公平鎖和非公平鎖。不過要記住,ReentrantReadWriteLock並未實現Lock介面,它實現的是ReadWriteLock介面。
4.讀寫鎖
讀寫鎖將對一個資源(比如文件)的訪問分成了2個鎖,一個讀鎖和一個寫鎖。
正因為有了讀寫鎖,才使得多個線程之間的讀操作不會發生沖突。
ReadWriteLock就是讀寫鎖,它是一個介面,ReentrantReadWriteLock實現了這個介面。
可以通過readLock()獲取讀鎖,通過writeLock()獲取寫鎖。
性能比較
在JDK1.5中,synchronized是性能低效的。因為這是一個重量級操作,它對性能最大的影響是阻塞的是實現,掛起線程和恢復線程的操作都需要轉入內核態中完成,這些操作給系統的並發性帶來了很大的壓力。相比之下使用Java提供的Lock對象,性能更高一些。Brian
Goetz對這兩種鎖在JDK1.5、單核處理器及雙Xeon處理器環境下做了一組吞吐量對比的實驗,發現多線程環境下,synchronized的吞吐量下降的非常嚴重,而ReentrankLock則能基本保持在同一個比較穩定的水平上。但與其說ReetrantLock性能好,倒不如說synchronized還有非常大的優化餘地,於是到了JDK1.6,發生了變化,對synchronize加入了很多優化措施,有自適應自旋,鎖消除,鎖粗化,輕量級鎖,偏向鎖等等。導致在JDK1.6上synchronize的性能並不比Lock差。官方也表示,他們也更支持synchronize,在未來的版本中還有優化餘地,所以還是提倡在synchronized能實現需求的情況下,優先考慮使用synchronized來進行同步。
⑧ 多線程的同步和互斥有什麼區別
舉例說明:
假如把整條道路看成是一個【進程】的話,那麼馬路中間白色虛線分隔開來的各個車道就是進程中的各個【線程】了。
①這些線程(車道)共享了進程(道路)的公共資源(土地資源)。
②這些線程(車道)必須依賴於進程(道路),也就是說,線程不能脫離於進程而存在(就像離開了道路,車道也就沒有意義了)。
③這些線程(車道)之間可以並發執行(各個車道你走你的,我走我的),也可以互相同步(某些車道在交通燈亮時禁止繼續前行或轉彎,必須等待其它車道的車輛通行完畢)。
④這些線程(車道)之間依靠代碼邏輯(交通燈)來控制運行,一旦代碼邏輯控制有誤(死鎖,多個線程同時競爭唯一資源),那麼線程將陷入混亂,無序之中。
⑤這些線程(車道)之間誰先運行是未知的,只有在線程剛好被分配到CPU時間片(交通燈變化)的那一刻才能知道。
註:
由於用於互斥的信號量sem與所有的並發進程有關,所以稱之為公有信號量。公有信號量的值反映了公有資源的數量。只要把臨界區置於P(sem)和V(sem)之間,即可實現進程間的互斥。就象火車中的每節車廂只有一個衛生間,該車廂的所有旅客共享這個公有資源:衛生間,所以旅客間必須互斥進入衛生間,只要把衛生間放在P(sem)和V(sem)之間,就可以到達互斥的效果。
⑨ synchronized實現何時使用了自旋鎖還是互斥鎖
synchronized的鎖是針對多線程的,從線程的角度去思考才能真正弄明白。
Java的synchronized使用方法總結
1. 把synchronized當作函數修飾符時
這也就是同步方法,那這時synchronized鎖定的是哪個對象呢?它鎖定的是調用這個同步方法對象。也就是說,當一個對象P1在不同的線程中執行這個同步方法時,它們之間會形成互斥,達到同步的效果。但是這個對象所屬的Class所產生的另一對象P2卻可以任意調用這個被加了synchronized關鍵字的方法。
同步塊,示例代碼如下:
public void method3(SomeObject so)
{
synchronized(so)
{
//…..
}
}
這時,鎖就是so這個對象,誰拿到這個鎖誰就可以運行它所控制的那段代碼。當有一個明確的對象作為鎖時,就可以這樣寫程序,但當沒有明確的對象作為鎖,只是想讓一段代碼同步時,可以創建一個特殊的instance變數(它得是一個對象)來充當鎖。
3.將synchronized作用於static 函數,示例代碼如下:
Class Foo
{
public synchronized static void methodAAA() // 同步的static 函數
{
//….
}
public void methodBBB()
{
synchronized(Foo.class) // class literal(類名稱字面常量)
}
}
代碼中的methodBBB()方法是把class literal作為鎖的情況,它和同步的static函數產生的效果是一樣的,取得的鎖很特別,是當前調用這個方法的對象所屬的類(Class,而不再是由這個Class產生的某個具體對象了)。