二、串行(同步):
1.lock、Monitor--注意锁定的对象必需是引用类型(string类型除外)
示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
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
示例:
1
2
3
4
5
6
7
8
9
10
11
12
|
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--可以实现进程间的同步,甚至是两个远程进程间的同步
示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
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--如果在某一时刻资源并没有获取写的独占权,那么可以获得多个读的访问权,单个写入的独占权,如果某一时刻已经获取了写入的独占权,那么其它读取的访问权必须进行等待.
示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
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对象
示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
[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--使整个方法上锁,直到方法返回,才释放锁
示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
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方法发送信号,事件将变为终止状态,等待的线程被唤醒
示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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(不可跨进程)--信号量,可实现线程、进程间同步
示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
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--屏障,使多个任务能够采用并行方式依据某种算法在多个阶段中协同工作,即:将一个阶段的事情分成多个线程来异步执行,执行完毕后再同时进入下一个阶段
示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
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--自旋锁,仅限锁定的时间较短
示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
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--自旋等待,轻量级
1
2
3
4
5
6
7
8
|
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支持动态调整信号计数
示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
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):
参考以下相关文章:
本文转自 梦在旅途 博客园博客,原文链接: http://www.cnblogs.com/zuowj/p/4910512.html ,如需转载请自行联系原作者