【java并发编程艺术学习】(二)第一章 java并发编程的挑战
章节介绍
主要介绍并发编程时间中可能遇到的问题,以及如何解决。
主要问题
1、上下文切换问题
时间片是cpu分配给每个线程的时间,时间片非常短。
cpu通过时间片分配算法来循环执行任务,当前任务执行一个时间片之后会切换到下一个任务。但是在切换之前会保存上一个任务的状态,以便再切换到这个任务时候,能够加载这个任务的状态。所以任务从保存再到加载的过程就是一次上下文切换。类似于读英文书时,遇到不懂的单词,记下读到的行数,翻出词典查询,查询完成后再翻到需要阅读的地方进行读取似的。
举例说明 多线程程序不一定是最快的。
1.1 代码示例:
1 package com.zhengze.test; 2 3 public class Test1 { 4 5 private static final long count = 10L; 6 7 /** 8 * 并行 9 * @throws InterruptedException 10 */ 11 public static void concurrency() throws InterruptedException { 12 long start = System.currentTimeMillis(); 13 Thread thread = new Thread(new Runnable() { 14 15 @Override 16 public void run() { 17 // TODO Auto-generated method stub 18 int a = 0; 19 for(long i =0;i<count;i++){ 20 a +=5; 21 } 22 } 23 }); 24 thread.start(); 25 int b = 0; 26 for(long i = 0; i<count ;i++){ 27 b--; 28 } 29 long time = System.currentTimeMillis() - start; 30 thread.join();//TODO 这个方法是做什么的? 31 32 System.out.println("时间:"+time+"===========b:"+b); 33 34 } 35 36 /** 37 * 串行 38 */ 39 public static void serial(){ 40 long start = System.currentTimeMillis(); 41 int a = 0; 42 for(long i = 0; i<count;i++){ 43 a +=5; 44 } 45 int b = 0; 46 for(long i = 0; i<count;i++){ 47 b --; 48 } 49 long time = System.currentTimeMillis() - start; 50 System.out.println("时间2:"+time +"------a:"+a+"=====b:"+b); 51 52 } 53 /** 54 * 测试示例 55 * @param args 56 * @throws InterruptedException 57 */ 58 public static void main(String[] args) throws InterruptedException { 59 concurrency(); 60 serial(); 61 62 } 63 64 }
代码示例,得出结论:多线程并不一定就比串行程序块!此处测试,数据量达到百万级别时候,多线程的速度会更好些。
具体,参照《java并发编程的艺术》中对应第一章节详细阅读。
1.2 减少上下文切换的方法
无锁并发编程、CAS算法、使用最少线程(比如任务很少,要避免创建不必要的线程来处理)、使用协程等。
(备注:这里需要补充下 协程 的知识点。。。。)
2、死锁
避免死锁的常见方法:
1、避免一个线程同时获取多个锁;
2、避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源;
3、尝试使用定时锁,使用 lock.tryLock(timeout)来替代使用内部锁机制;
4、对于数据库锁,加锁和解锁必须在用一个数据库连接里,否则会出现解锁失败的情况。
3、资源(软硬件等)限制的挑战
主要分为硬件资源限制和 软件资源限制:
硬件资源限制:主要为宽带的上传/下载速度、磁盘的读写速度、cpu的处理速度等;
软件资源限制:主要为数据库的连接数、socket的连接数等。
小节
笔者强烈推荐使用JDK并发包中提供的并发容器和工具类来解决并发问题。
(正在系统的学习下这部分的。)