二、串行(同步):
1.lock、Monitor--注意鎖定的對象必需是引用類型(string類型除外)
示例:
private static object syncObject = new object();
private static void TaskWork(object i)
{
Console.WriteLine("我是任務:{0}",i);
lock (syncObject)
{
Thread.Sleep(1000);
Console.WriteLine("我是任務:{0},線程ID:{1}",i,Thread.CurrentThread.ManagedThreadId);
}
try
{
Monitor.Enter(syncObject);
Console.WriteLine("我是任務:{0},線程ID:{1}", i, Thread.CurrentThread.ManagedThreadId);
}
finally
{
Monitor.Exit(syncObject);
}
}
//調用
Task.Factory.StartNew(TaskWork,1);
Task.Factory.StartNew(TaskWork, 2);
2.Interlocked
示例:
int i=1;
Interlocked.Increment(ref i); //增量+1=2;
Console.WriteLine("i當前的值:{0}", i);
Interlocked.Decrement(ref i); //減量-1=0;
Console.WriteLine("i當前的值:{0}", i);
Interlocked.Exchange(ref i, 2);//賦值=2;
Console.WriteLine("i當前的值:{0}",i);
Interlocked.CompareExchange(ref i, 10, 2);//比較交換值,當i=2時,則將i賦值為10;
Console.WriteLine("i當前的值:{0}", i);
3.Mutex--可以實現進程間的同步,甚至是兩個遠程進程間的同步
示例:
var t1 = new Task(() =>
{
Console.WriteLine("我是第一個任務!");
Mutex m = new Mutex(false, "test");
m.WaitOne();
Console.WriteLine("第一個任務完成!");
m.ReleaseMutex();
});
var t2 = new Task(() =>
{
Console.WriteLine("我是第二個任務!");
Mutex m = new Mutex(false, "test");
m.WaitOne();
Console.WriteLine("第二個任務完成!");
m.ReleaseMutex();
});
t1.Start();
t2.Start();
4.ReaderWriterLock 、ReaderWriterLockSlim--如果在某一時刻資源並沒有獲取寫的獨占權,那麼可以獲得多個讀的訪問權,單個寫入的獨占權,如果某一時刻已經獲取了寫入的獨占權,那麼其它讀取的訪問權必須進行等待.
示例:
static ReaderWriterLock rwLock = new ReaderWriterLock();
static void Read(object state)
{
Console.WriteLine("我是讀線程,線程ID是:{0}",Thread.CurrentThread.ManagedThreadId);
rwLock.AcquireReaderLock(Timeout.Infinite);//無限期等待,需要顯式調用ReleaseReaderLock釋放鎖
var readList = state as IEnumerable<int>;
foreach (int item in readList)
{
Console.WriteLine("讀取當前的值為:{0}", item);
Thread.Sleep(500);
}
Console.WriteLine("讀完成,線程ID是:{0}", Thread.CurrentThread.ManagedThreadId);
rwLock.ReleaseReaderLock();
}
static void Write(object state)
{
Console.WriteLine("我是寫線程,線程ID是:{0}", Thread.CurrentThread.ManagedThreadId);
rwLock.AcquireWriterLock(Timeout.Infinite); //無限期等待,需要顯式調用ReleaseWriterLock釋放鎖
var writeList = state as List<int>;
int lastCount=writeList.Count();
for (int i = lastCount; i <= 10+lastCount; i++)
{
writeList.Add(i);
Console.WriteLine("寫入當前值:{0}",i);
Thread.Sleep(500);
}
Console.WriteLine("寫完成,線程ID是:{0}", Thread.CurrentThread.ManagedThreadId);
rwLock.ReleaseWriterLock();
}
//調用:
var rwList = new List<int>();
var t1 = new Thread(Write);
var t2 = new Thread(Read);
var t3 = new Thread(Write);
var t4 = new Thread(Read);
t1.Start(rwList);
t2.Start(rwList);
t3.Start(rwList);
t4.Start(rwList);
5.SynchronizationAttribute--確保某個類的實例在同一時刻只能被一個線程訪問,類的定義要求:A.類上必需標記SynchronizationAttribute特性,B.類必需繼承自System.ContextBoundObject對象
示例:
[Synchronization(SynchronizationAttribute.REQUIRED,true)]
public class Account : System.ContextBoundObject
{
private static int _balance;
public int Blance
{
get
{
return _balance;
}
}
public Account()
{
_balance = 1000;
}
public void WithDraw(string name,object money)
{
if ((int)money <= _balance)
{
Thread.Sleep(2000);
_balance = _balance - (int)money;
Console.WriteLine("{0} 取錢成功!余額={1}", name, _balance);
}
else
{
Console.WriteLine("{0} 取錢失敗!余額不足!", name);
}
}
}
//調用:
var account = new Account();
Parallel.Invoke(() =>
{
account.WithDraw("張三",600);
}, () =>
{
account.WithDraw("李四",600);
});
6.MethodImplAttribute--使整個方法上鎖,直到方法返回,才釋放鎖
示例:
public class Account
{
private static int _balance;
public int Blance
{
get
{
return _balance;
}
}
public Account()
{
_balance = 1000;
}
[MethodImpl(MethodImplOptions.Synchronized)]
public void WithDraw(string name,object money)
{
if ((int)money <= _balance)
{
Thread.Sleep(2000);
_balance = _balance - (int)money;
Console.WriteLine("{0} 取錢成功!余額={1}", name, _balance);
}
else
{
Console.WriteLine("{0} 取錢失敗!余額不足!", name);
}
}
}
//調用
var account = new Account();
Parallel.Invoke(() =>
{
account.WithDraw("張三",600);
}, () =>
{
account.WithDraw("李四",600);
});
7.AutoResetEvent、ManualResetEvent、ManualResetEventSlim--調用WaitOne、WaitAny或WaitAll來使線程等待事件,調用Set方法發送信號,事件將變為終止狀態,等待的線程被喚醒
示例:
AutoResetEvent arEvent = new AutoResetEvent(false);//默認為無信號,處於非終止狀態
Task.Factory.StartNew((o) => {
for (int i = 1; i <= 10; i++)
{
Console.WriteLine("循環第{0}次",i);
}
arEvent.Set();//發送信號,處於終止狀態
},arEvent);
arEvent.WaitOne();//等待信號,收到信號後則繼續下面的執行
Console.WriteLine("我是主線程,我繼續執行!");
Console.Read();
8.Sempaphore、SemaphoreSlim(不可跨進程)--信號量,可實現線程、進程間同步
示例:
public class WashRoom
{
private readonly Semaphore sem;
public WashRoom(int maxUseableCount)
{
sem = new Semaphore(maxUseableCount, maxUseableCount, "WC");
}
public void Use(int i)
{
Task.Factory.StartNew(() =>
{
Console.WriteLine("第{0}個人等待進入", i);
// WaitOne:如果還有“空位”,則占位,如果沒有空位,則等待;
sem.WaitOne();
Console.WriteLine("第{0}個人成功進入,使用中", i);
// 模擬線程執行了一些操作
Thread.Sleep(100);
Console.WriteLine("第{0}個人用完,離開了", i);
// Release:釋放一個“空位”
sem.Release();
});
}
}
//調用:
var wc = new WashRoom(5);
for (int i = 1; i <= 7; i++)
{
wc.Use(i);
}
9.Barrier--屏障,使多個任務能夠采用並行方式依據某種算法在多個階段中協同工作,即:將一個階段的事情分成多個線程來異步執行,執行完畢後再同時進入下一個階段
示例:
int taskSize = 5;
Barrier barrier = new Barrier(taskSize, (b) =>
{
Console.WriteLine(string.Format("{0}當前階段編號:{1}{0}", "-".PadRight(15, '-'), b.CurrentPhaseNumber));
});
var tasks = new Task[taskSize];
for (int i = 0; i < taskSize; i++)
{
tasks[i] = Task.Factory.StartNew((n) =>
{
Console.WriteLine("Task : #{0} ----> 處理了第一部份數據。", n);
barrier.SignalAndWait();
Console.WriteLine("Task : #{0} ----> 處理了第二部份數據。", n);
barrier.SignalAndWait();
Console.WriteLine("Task : #{0} ----> 處理了第三部份數據。", n);
barrier.SignalAndWait();
}, i);
}
Task.WaitAll(tasks);
10.SpinLock--自旋鎖,僅限鎖定的時間較短
示例:
SpinLock sLock = new SpinLock();
int num = 0;
Action action = () =>
{
bool lockTaken = false;
for (int i = 0; i < 10; i++)
{
lockTaken = false;
try
{
sLock.Enter(ref lockTaken);
Console.WriteLine("{0}+1={1} ---線程ID:[{2}]", num, ++num,Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(new Random().Next(9));
}
finally
{
//真正獲取之後,才釋放
if (lockTaken) sLock.Exit();
}
}
};
//多線程調用:
Parallel.Invoke(action, action, action);
Console.WriteLine("合計:{0}", num);
11.SpinWait--自旋等待,輕量級
Thread.Sleep(1000);//線程等待1S;
Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
SpinWait.SpinUntil(() => false, 1000);//自旋等待1S
Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
Thread.SpinWait(100000);//指定CPU的循環次數,時間間隔處決於處理器的運行速度,一般不建議使用
Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
12.CountdownEvent--與Sempaphore功能類似,但CountdownEvent支持動態調整信號計數
示例:
static void TimeLimitShopping(int custCount,int times,CountdownEvent countdown)
{
var customers = Enumerable.Range(1, custCount);
foreach (var customer in customers)
{
int currentCustomer = customer;
Task.Factory.StartNew(()=>
{
SpinWait.SpinUntil(() => false, 1000);
Console.WriteLine("第{0}波客戶購買情況:Customer-{1}-已購買.", times, currentCustomer);
countdown.Signal();
});
//countdown.AddCount();
}
}
//調用:
var countdown = new CountdownEvent(5);
TimeLimitShopping(5, 1, countdown);
countdown.Wait();
countdown.Reset(10);
TimeLimitShopping(10, 2, countdown);
countdown.Wait();
countdown.Reset(20);
TimeLimitShopping(20, 3, countdown);
countdown.Wait();
最後分享在System.Collections.Concurrent命名空間下的幾個並發集合類:
ConcurrentBag<T>:表示線程安全的無序集合;
ConcurrentDictionary<T>:表示線程安全的多個鍵值對集合;
ConcurrentQueue<T>:表示線程安全的先進先出集合;
ConcurrentStack<T>:表示線程安全的後進先出集合;
線程的幾個狀態(以下圖片來源於這篇文章:http://www.cnblogs.com/edisonchou/p/4848131.html):

參考以下相關文章:
歸納一下:C#線程同步的幾種方法
C#編程總結(三)線程同步