挑战一:上下文切换
多线程一定比单线程快么?
public class ConcurrencyTest { private static final long count = 10001; 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, b = " + b); } 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, b = " + b + ", a=" + a); } }
输出
答案是并不一定,当测试量达到一百万的时候,并发才能比串行优势点(本代码环境结果);
线程创建和上下文切换都是需要开销的。
如何减少上下文的切换?
- 无锁并发编程:可以使用一些方法避免使用锁,如将数据的ID按照Hash算法取模分段,不同的线程处理不同段的数据。
- CAS算法:Java的Atomic包使用CAS算法更新数据,而不需要加锁。
- 使用最少线程:避免创建不需要的线程。
- 协程:在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换。
挑战二:死锁
public class DeadLockDemo { private static String A = "A"; private static String B = "B"; public static void main(String[] args) { new DeadLockDemo().deadLock(); } private void deadLock(){ Thread thread1 = new Thread(new Runnable() { @Override public void run() { synchronized (A){ try { Thread.sleep(2000); } catch (InterruptedException e){ e.printStackTrace(); } synchronized (B){ System.out.println("1"); } } } }); Thread thread2 = new Thread(new Runnable() { @Override public void run() { synchronized (B){ synchronized (A){ System.out.println("2"); } } } }); thread1.start(); thread2.start(); } }
避免死锁的几个常见方法:
- 避免一个线程同时获取多个锁
- 避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占一个资源
- 尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制
- 对于数据库锁,加锁和解锁必须在一个数据库连接里
挑战三:资源限制的挑战
(1) 什么是资源限制?
指在进行并发编程时,程序的执行速度受限于计算机硬件资源或软件资源。
(2) 资源限制引发的问题?
在并发编程中,将代码执行速度加快的原则是将代码中串行的部分变成并发执行,但是如果将某段串行的代码并发执行,因为受限于资源,仍然在串行执行,这时候程序不仅不会加快执行,反而会更慢,因为增加了上下文切换和资源调度的时间。
(3)如何解决资源限制的问题?
对于硬件限制,可以考虑集群并行执行程序。既然单机的资源有限制,就让程序在多机上运行。比如使用ODPS、Hadoop或者自己搭建服务器集群;
对于软件限制,可以考虑使用资源池将资源复用。比如使用连接池将数据库和Socket连接复用,或者在调用对方webService接口获取数据时,只建立一个连接。
(4)如何在资源限制的情况下进行并发编程?
根据不同的资源限制调整程序的并发度,比如下载文件程序依赖于两个资源——宽带和硬盘读写速度。有数据库操作时,设计数据库连接数,如果SQL语句执行非常快,而线程的数量比数据库连接数大很多,则某些线程会被阻塞,等待数据库连接。
原文地址:https://www.cnblogs.com/hzzjj/p/9678064.html
时间: 2024-11-05 22:41:34