并发编程中下面的这些概念是非常关键的:
- 同步与异步
- 并行与并发
- 临界区
- 阻塞与非阻塞
- 死锁、活锁与饥饿
1. 同步与异步
是针对方法调用的,同步是等方法执行完再继续执行,异步是调用之后立即返回,不等方法执行完成,由一个新的线程去执行。
就像你去一个商店买东西,没货了,需要去仓库取货。
如果是同步方式,你就在店里等,取回货之后,你带着货离开。
如果是异步方式,你不等,把送货地址留下后就走了。
2. 并行与并发
他们给人的感觉是一样的,都是多个任务在一起执行,但实际是有区别的,并行是真正的一起执行,并发是交替执行,让人感觉是在同时一起执行。
单核CPU只能并发,多个任务交替执行,多核才能并行。
3. 临界区
临界区是一个公共的共享资源,都可以用,但同一时刻只能一个人使用,其他人必须等待。
例如公司的一个打印机,就是临界区,同事们都可以用它打印文件,但一次只能打印一份,小王正在打印,别的同事就得等他打完。
4. 阻塞与非阻塞
是针对临界区的,一个线程拿到了临界区资源,其他线程如果一直等着它完事儿,就是阻塞,如果其他线程不等,继续干别的事儿,这就是非阻塞。
5. 死锁、活锁与饥饿
死锁很好理解,线程1持有资源A,线程2持有资源B,然后线程1要拿B,线程2要拿A,都想要对方的资源,又都不放开自己手里的资源,这就僵死了。
public void a_b()
{
synchronized (res_a)
{
synchronized (res_b)
{
// ...
}
}
}
public void b_a()
{
synchronized (res_b)
{
synchronized (res_a)
{
// ...
}
}
}
死锁是线程拿不到资源,处于等待状态,不动了,像死了一样,活锁也是等待资源,但线程是处于活跃状态,一直重试,看资源是否可用,失败后继续重试,是死循环的状态。
// Thread1
Thread.Start( ()=> {
while (true) {
if (!l1.Lock(1000)) {
continue;
}
if (!l2.Lock(1000)) {
continue;
}
// do some work
}
);
// Thread2
Thread.Start( ()=> {
while (true) {
if (!l2.Lock(1000)) {
continue;
}
if (!l1.Lock(1000)) {
continue;
}
// do some work
}
);
饥饿是线程一直拿不到资源,原因是它的优先级太低,资源一直被高优先级的线程抢来抢去,它被眼睁睁的饿死了。
网友评论