> 文档中心 > 01Java并发编程的艺术之并发编程的挑战

01Java并发编程的艺术之并发编程的挑战


一、上下文切换

1、并发编程真的快吗?什么是上下文切换?

答案是不一定,根据测试结果,当数据小于百万的时候并发并没有串行快,这是为什么那?单核处理器的多线程并发,其实就是CPU个每个线程分配时间片,当时间片执行完就需要切换另一个线程的时间片来执行,时间片是非常小的单位,所以我们会觉得是并发!而他们发生切换的时候需要保存当前状态,然后在切换,而保存在切换之后的重新加载就是上下文切换,这也是比较浪费时间的!

public class Demo01 {    /**     * count = 10000001:     *  concurrency:31ms,b:-50000005     *  serial:39ms,b:-50000005,a:50000005     *     * count = 1000001;     *  concurrency:17ms,b:-500005     *  serial:12ms,b:-500005,a:500005     *    * count = 100001;     *  concurrency:11ms,b:-500005     *  serial:8ms,b:-500005,a:500005     */    private static final long count = 1000001;    public static void concurrency() throws InterruptedException { long startTime = System.currentTimeMillis(); Thread thread = new Thread(new Runnable() {     @Override     public void run() {  int a = 0;  for (int i = 0; i < count; i++){      a += 5;  }     } }); thread.start(); int b = 0; for (int i = 0; i < count; i++){     b -= 5; } thread.join(); long time = System.currentTimeMillis() - startTime; System.out.println("concurrency:" + time + "ms,b:" + b);    }    public static void serial(){ long startTime = System.currentTimeMillis(); int a = 0; for (int i = 0; i < count; i++){     a += 5; } int b = 0; for (int i = 0; i < count; i++){     b -= 5; } long time = System.currentTimeMillis() - startTime; System.out.println("serial:" + time + "ms,b:" + b + ",a:" + a);    }    public static void main(String[] args) throws InterruptedException { concurrency(); serial();    }}

2、如何减少上下文切换?

  • 使用无锁并发编程,没有锁的话就会减少线程之间的竞争,从而减少上下文切换!
  • 使用CAS算法,使用CAS更新值无需加锁!
  • 使用最少线程,尽量减少线程的时候从而避免上下文切换!
  • 协程,可以试试单线程维护多个任务的切换!

二、死锁

1、什么是死锁?

线程之间都拿着对方需要的资源,并且都不是释放资源,从而导致死锁!例如两个共享资源A和B,第一个线程先拿到A后锁住A,准备拿B,但是在第一个线程准备拿B的时候,第二个线程已经拿到B并且锁住,然后准备去拿资源A,这时候就发生了死锁了!这就是死锁!

public class Demo02 {    private static String a = "a";    private static String b = "b";    public static void main(String[] args) { Thread thread_A = new Thread(new Runnable() {     @Override     public void run() {  synchronized (a){      try {   TimeUnit.SECONDS.sleep(2000);      } catch (InterruptedException e) {   e.printStackTrace();      }      synchronized (b){   System.out.println(Thread.currentThread().getName());      }  }     } },"Thread_A"); Thread thread_B = new Thread(new Runnable() {     @Override     public void run() {  synchronized (b){      synchronized (a){   System.out.println(Thread.currentThread().getName());      }  }     } }, "Thread_B"); thread_A.start(); thread_B.start();    }}

2、如何避免死锁

  • 避免一个线程获取多个锁
  • 避免一个线程同时占用多个资源
  • 使用定时锁,例如lock.tryLock();
  • 使用数据库锁,加解锁都是在一个数据库连接当中!

感谢大家的阅读,我是Alson_Code,一个喜欢把简单问题复杂化,把复杂问题简单化的程序猿!