并发编程的目的是为了让程序运行的更快
并发编程面临的挑战
一、上下文切换问题
二、死锁问题
三、资源受限问题
(一)上下文切换
CPU通过给每个线程分配CPU时间片(几十毫秒)来实现多线程。
CPU通过时间片分配算法来循环执行任务。任务从保存到再加载的过程就是一次上下文切换。但是,多线程不一定快,测试代码如下:
/**
* 并发和单线程执行测试
*/
public class ConcurrencyTest {
/** 执行次数 */
private static final long count = 100000000l;
public static void main(String[] args) throws InterruptedException {
//并发计算
concurrency();
//单线程计算
serial();
}
private static void concurrency() throws InterruptedException {
long start = System.currentTimeMillis();
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
int a = 0;
for (long i = 0; i < count; i++) {
a += 5;
}
}
});
thread.start();
int b = 0;
for (long i = 0; i < count; i++) {
b--;
}
thread.join();
long time = System.currentTimeMillis() - start;
System.out.println("concurrency :" + time + "ms");
}
private static void serial() {
long start = System.currentTimeMillis();
int a = 0;
for (long i = 0; i < count; i++) {
a += 5;
}
int b = 0;
for (long i = 0; i < count; i++) {
b--;
}
long time = System.currentTimeMillis() - start;
System.out.println("serial:" + time + "ms" );
}
}
当count = 100000000l时,输出结果:
concurrency :48ms
serial:74ms
当count = 10000l;时,输出结果:
concurrency :1ms
serial:0ms
从上述试验结果可知:多线程不一定快,使用多线程得在合适的场合。
如何减少上下文切换:
1、无锁并发编程
2、CAS算法(比较并交换)
3、使用最少线程
4、协程
(二)死锁
在多任务系统下,当一个或多个进程等待系统资源,而资源又被进程本身或其它进程占用时,就形成了死锁。死锁会造成系统功能不可用。下面举一个典型的例子来说明死锁问题:
/**
* 死锁例子
*/
public class DeadLockDemo {
/** A锁 */
private static String A = "A";
/** B锁 */
private static String B = "B";
public static void main(String[] args) {
new DeadLockDemo().deadLock();
}
private void deadLock() {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (A) {
try {
System.out.println("线程t1获得A锁,准备去拿B锁");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (B) {
System.out.println("线程t1获得B锁");
}
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (B) {
System.out.println("线程t2获得B锁,准备去拿A锁");
synchronized (A) {
System.out.println("线程t2获得A锁");
}
}
}
});
t1.start();
t2.start();
}
}
输出结果:
线程t1获得A锁,准备去拿B锁
线程t2获得B锁,准备去拿A锁
避免死锁的几个方法:
1、避免一个线程同时获得多个锁
2、尽量每个锁占用一个资源
3、用定时锁替代内部锁机制
4、对于数据库锁,加解锁必须在一个数据库连接里,否则会解锁失败
(三)资源受限
资源限制是指在并发编程时,程序的执行速度受限于软硬件资源。
将某段串行代码并发执行,因为资源受限,代码实际上并发度不高,反而增加了上下文切换和资源调度的时间。
硬件资源
带宽的上传下载,硬盘读写速度,CPU的处境速度等
解决方法:服务器集群
软件资源
数据库连接数,socket连接数等
解决方法:使用资源池将资源复用
网友评论