網(wǎng)站首頁 編程語言 正文
一、簡介
線程安全概念:線程安全是指在當(dāng)一個線程訪問該類的某個數(shù)據(jù)時,進(jìn)行保護(hù),其他線程不能進(jìn)行訪問直到該線程讀取完,其他線程才可使用。不會出現(xiàn)數(shù)據(jù)不一致或者數(shù)據(jù)污染。
線程有可能和其他線程共享一些資源,比如,內(nèi)存,文件,數(shù)據(jù)庫等。當(dāng)多個線程同時讀寫同一份共享資源的時候,可能會引起沖突。這時候,我們需要引入線程“同步”機制,即各位線程之間要有個先來后到,不能一窩蜂擠上去搶作一團(tuán)。線程同步的真實意思和字面意思恰好相反。線程同步的真實意思,其實是“排隊”:幾個線程之間要排隊,一個一個對共享資源進(jìn)行操作,而不是同時進(jìn)行操作。
二、代碼
下面將通過簡單的四個案例進(jìn)行對比,來講解LOCK的實現(xiàn)線程同步使用。
案例一:
首先創(chuàng)建兩個線程,兩個線程執(zhí)行同一個方法,代碼如下:
class Program
{
static void Main(string[] args)
{
Thread threadA = new Thread(ThreadMethod); //執(zhí)行的必須是無返回值的方法
threadA.Name = "threadA";
Thread threadB = new Thread(ThreadMethod); //執(zhí)行的必須是無返回值的方法
threadB.Name = "threadB";
threadA.Start();
threadB.Start();
Console.ReadKey();
}
public static void ThreadMethod(object parameter)
{
for (int i = 1; i <= 10; i++)
{
Console.WriteLine("我是:{0},我循環(huán){1}次", Thread.CurrentThread.Name, i);
Thread.Sleep(1000);//休眠一秒
}
}
}
通過下面的執(zhí)行結(jié)果,可以很清楚的看到,兩個線程是在同時執(zhí)行ThreadMethod這個方法,這顯然不符合我們線程同步的要求。
執(zhí)行結(jié)果:
案例二:
通過對上面代碼的修改如下:
class Program
{
static void Main(string[] args)
{
Program pro = new Program();
Thread threadA = new Thread(pro.ThreadMethod);
threadA.Name = "threadA";
Thread threadB = new Thread(pro.ThreadMethod);
threadB.Name = "threadB";
threadA.Start();
threadB.Start();
Console.ReadKey();
}
public void ThreadMethod(object parameter)
{
lock (this) //添加lock關(guān)鍵字
{
for (int i = 1; i <= 10; i++)
{
Console.WriteLine("我是:{0},我循環(huán){1}次", Thread.CurrentThread.Name, i);
Thread.Sleep(1000);//休眠一秒
}
}
}
}
執(zhí)行結(jié)果:
?
我們通過添加了 lock(this) {...}代碼,查看執(zhí)行結(jié)果實現(xiàn)了我們想要的線程同步需求。
案例三:
但是我們知道this表示當(dāng)前類實例的本身,那么有這么一種情況,我們把需要訪問的方法所在的類型進(jìn)行兩個實例A和B,線程A訪問實例A的方法ThreadMethod,線程B訪問實例B的方法ThreadMethod,這樣的話還能夠達(dá)到線程同步的需求嗎?
修改后的代碼如下:
class Program
{
static void Main(string[] args)
{
Program pro1 = new Program();
Program pro2 = new Program();
Thread threadA = new Thread(pro1.ThreadMethod);
threadA.Name = "threadA";
Thread threadB = new Thread(pro2.ThreadMethod);
threadB.Name = "threadB";
threadA.Start();
threadB.Start();
Console.ReadKey();
}
public void ThreadMethod(object parameter)
{
lock (this) //添加lock關(guān)鍵字
{
for (int i = 1; i <= 10; i++)
{
Console.WriteLine("我是:{0},我循環(huán){1}次", Thread.CurrentThread.Name, i);
Thread.Sleep(1000);//休眠一秒
}
}
}
}
執(zhí)行結(jié)果:
我們會發(fā)現(xiàn),線程又沒有實現(xiàn)同步了!lock(this)對于這種情況是不行的!
案例四:
通過對上面代碼再次進(jìn)行如下修改:
class Program
{
private static object obj = new object();
static void Main(string[] args)
{
Program pro1 = new Program();
Program pro2 = new Program();
Thread threadA = new Thread(pro1.ThreadMethod);
threadA.Name = "threadA";
Thread threadB = new Thread(pro2.ThreadMethod);
threadB.Name = "threadB";
threadA.Start();
threadB.Start();
Console.ReadKey();
}
public void ThreadMethod(object parameter)
{
lock (obj) //添加lock關(guān)鍵字
{
for (int i = 1; i <= 10; i++)
{
Console.WriteLine("我是:{0},我循環(huán){1}次", Thread.CurrentThread.Name, i);
Thread.Sleep(1000);//休眠一秒
}
}
}
}
執(zhí)行結(jié)果:
通過查看執(zhí)行結(jié)果。會發(fā)現(xiàn)代碼實現(xiàn)了我們的需求。
那么 lock(this) 和lock(Obj)有什么區(qū)別呢?
lock(this) 鎖定 當(dāng)前實例對象,如果有多個類實例的話,lock鎖定的只是當(dāng)前類實例,對其它類實例無影響。所有不推薦使用。
lock(typeof(Model))鎖定的是model類的所有實例。
lock(obj)鎖定的對象是全局的私有化靜態(tài)變量。外部無法對該變量進(jìn)行訪問。
lock 確保當(dāng)一個線程位于代碼的臨界區(qū)時,另一個線程不進(jìn)入臨界區(qū)。如果其他線程試圖進(jìn)入鎖定的代碼,則它將一直等待(即被阻止),直到該對象被釋放。
所以,lock的結(jié)果好不好,還是關(guān)鍵看鎖的誰,如果外邊能對這個誰進(jìn)行修改,lock就失去了作用。所以一般情況下,使用私有的、靜態(tài)的并且是只讀的對象
三、總結(jié)
- 1.lock的是必須是引用類型的對象,string類型除外。
- 2.lock推薦的做法是使用靜態(tài)的、只讀的、私有的對象。
- 3.保證lock的對象在外部無法修改才有意義,如果lock的對象在外部改變了,對其他線程就會暢通無阻,失去了lock的意義。
不能鎖定字符串,鎖定字符串尤其危險,因為字符串被公共語言運行庫 (CLR)“暫留”。 這意味著整個程序中任何給定字符串都只有一個實例,就是這同一個對象表示了所有運行的應(yīng)用程序域的所有線程中的該文本。因此,只要在應(yīng)用程序進(jìn)程中的任何位置處具有相同內(nèi)容的字符串上放置了鎖,就將鎖定應(yīng)用程序中該字符串的所有實例。通常,最好避免鎖定 public 類型或鎖定不受應(yīng)用程序控制的對象實例。例如,如果該實例可以被公開訪問,則 lock(this) 可能會有問題,因為不受控制的代碼也可能會鎖定該對象。這可能導(dǎo)致死鎖,即兩個或更多個線程等待釋放同一對象。出于同樣的原因,鎖定公共數(shù)據(jù)類型(相比于對象)也可能導(dǎo)致問題。而且lock(this)只對當(dāng)前對象有效,如果多個對象之間就達(dá)不到同步的效果。lock(typeof(Class))與鎖定字符串一樣,范圍太廣了。
原文鏈接:https://www.cnblogs.com/wml-it/p/14821998.html
相關(guān)推薦
- 2022-07-25 python如何將自己的包上傳到PyPi并可通過pip安裝的方法步驟_python
- 2022-03-27 ASP.NET?HttpRequest類介紹_基礎(chǔ)應(yīng)用
- 2023-01-09 python自動化測試中裝飾器@ddt與@data源碼深入解析_python
- 2022-11-22 Android?10?啟動分析之init語法詳解_Android
- 2022-06-22 Git的撤銷、修改和回退命令_其它綜合
- 2022-12-13 sql索引失效的情況以及超詳細(xì)解決方法_MsSql
- 2022-11-05 ios開發(fā)?try-catch引起的野指針問題排查_IOS
- 2022-08-17 Python?pandas.replace的用法詳解_python
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支