Java教程

第一章 并发编程的挑战

本文主要是介绍第一章 并发编程的挑战,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

第1章 并发编程挑战

并发编程的目的是为了使程序运行更快,但是,并不意味着启动更多线程就可让程序最大限度并发执行

1.1 上下文切换

CPU为不同线程分配不同的时间块来支持多线程执行代码(类似于时分复用),但是在切换到下一个任务之前,会将现在这个任务状态保存,以便下次可以再加载这个任务状态。任务从保存到再加载的过程就称为依次上下文切换

package com.chapter1;

import static java.lang.System.currentTimeMillis;

public class ConcurrentTest {
    private static long count = 100000000;
    public static void main(String[] args) throws InterruptedException {
        concurrency();
        serial();
    }
    //并发计算结果
    private static void concurrency() throws InterruptedException {
        long start = currentTimeMillis();
        //开启一个线程计算结果
        Thread thread = new Thread(()->{
            long sum = 0;
            for (int i = 0; i < count; i++) {
                sum = sum + 5;
            }
        });
        thread.start();
        //主线程循环减
        int b = 0;
        for (int i = 0; i < count; i++) {
            b--;
        }
        //插队
        thread.join();
        long time = System.currentTimeMillis() - start;
        System.out.println("concurrency:" + time);
    }
    //普通单线程计算
    private static void serial() {
        long start = System.currentTimeMillis();
        long sum = 0;
        for (int i = 0; i < count; i++) {
            sum = sum + 5;
        }
        int b = 0;
        for (int i = 0; i < count; i++) {
            b--;
        }
        long time = System.currentTimeMillis() - start;
        System.out.println("serial:" + time);

    }

}

通过例子发现,随着count的值增加,多线程优势逐渐显现出来,在count较小时,所用时间大于单线程时间。经过分析发现,这是因为上下文切换带来的时间损耗。

1.2 减少上下文切换

减少上下文切换方法有:无锁并发编程,CAS算法,使用最少线程和使用协程

  • 无锁并发编程:多个线程竞争锁时,会引发上下文切换,因此使用一些方法来避免使用锁
  • CAS算法:Java的Atomic包使用CAS算法更新数据,不需要加锁
  • 使用最少线程:即尽量少使用线程,避免创建过多不需要的线程
  • 协程:在单线程中实现多任务的调度

1.3 死锁

死锁产生的四个必要条件:

  • 互斥条件:一个资源被一个进程占用
  • 请求与保持条件:一个资源请求对方资源陷入等待,另一个线程不释放资源
  • 不剥夺条件:进程获得的资源在未释放之前不可被强行剥夺
  • 循环等待条件:若干进程间形成循环等待关系
package com.chapter1;

import java.util.concurrent.TimeUnit;

public class DeadLockTest {
    //两个资源
    private static String A = "A";
    private static String B = "B";

    public static void main(String[] args) {
        deadlock();
    }

    private static void deadlock() {
        //开启t1线程
        new Thread(()->{
            synchronized (A) {
                System.out.println(Thread.currentThread().getName() + "get A");
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (B) {
                    System.out.println(Thread.currentThread().getName() + "get B");
                }
            }
        }, "t1").start();

        //开启t2线程
        new Thread(()->{
            synchronized (B) {
                System.out.println(Thread.currentThread().getName() + "get B");
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (A) {
                    System.out.println(Thread.currentThread().getName() + "get A");
                }
            }
        }, "t2").start();
    }


}

避免死锁的几个常用方法:

  • 避免一个线程获得多个锁
  • 避免一个线程在锁内占用多个资源,尽量保证每个锁仅占用一个资源
  • 使用定时锁(lock.tryLock(timeout))来代替内部锁
  • 对于数据库锁,加锁和解锁必须在同一个数据库连接中

1.4 资源限制问题

什么是资源限制

资源限制是指在并发编程中,程序执行速度受限于计算机硬件资源或软件资源

资源限制引发的问题

并发编程的原则是将代码中串行执行的部分编程并发执行。但由于资源限制问题,本质上还是串行,同时由于上下文切换和资源调度问题,时间反而会增加。

如何解决资源限制问题

硬件资源限制:使用集群并行执行程序。让程序在多个计算机上执行,比如使用ODPS,Hadoop搭建服务器集群

软件资源限制:使用资源池将资源复用。

资源限制下的并发编程

在资源限制下,根据不同的资源限制调整程序的并发度。

这篇关于第一章 并发编程的挑战的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!