《并发编程的艺术》第一章 并发编程的挑战

本文探讨了并发编程中的上下文切换、死锁及资源限制等问题,并提供了减少上下文切换次数、避免死锁以及解决资源限制问题的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.1 上下文切 

CPU过时间片分配算法来循环执行任,当前任务执行一个时间片后会切到下一个 任务。但是,在切前会保存上一个任的状,以便下次切个任务时,可以再加载这 个任务的状。所以任从保存到再加程就是一次上下文切

1.1.1 线程一定快

public class Test01 {
    private static final long count = 10000l;

    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() {
            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--;
        }
        long time = System.currentTimeMillis() - start;
        //join() 的作用:让“主线程”等待“子线程”结束之后才能继续运行。
        thread.join();
        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);
    }
}

1.1.2 测试上下文切次数和时长 

·使用Lmbench3[1]可以量上下文切时长
·使用vmstat可以量上下文切的次数。

 1.1.3 如何减少上下文切

减少上下文切的方法有无发编程、CAS算法、使用最少线程和使用程。
 
·发编程。多线锁时,会引起上下文切,所以多线理数据,可以用一 些办法来避免使用,如将数据的ID按照Hash算法取模分段,不同的线理不同段的数据。
 
·CAS算法。JavaAtomic包使用CAS算法来更新数据,而不需要加
 
·使用最少线程。避免建不需要的线程,比如任很少,但是建了很多线程来理,这 样会造成大量线程都于等待状
 
·程:在单线程里实现多任度,并在单线程里持多个任务间的切

1.1.4 减少上下文切换实战

1.2

段代会引起死,使线t1线t2互相等待

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 t1 = new Thread(new Runnable() {
            public void run() {
                synchronized (A) {
                    try {
                        Thread.currentThread().sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (B) {
                        System.out.println("1");
                    }
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            public void run() {
                synchronized (B) {
                    synchronized (A) {
                        System.out.println("2");
                    }
                }
            }
        });
        t1.start();
        t2.start();
    }
}
段代只是演示死景,在现实中你可能不会写出这样的代。但是,在一些更为 复杂景中,你可能会遇到这样问题,比如t1拿到锁之后,因为一些异常情况没有释放锁 (死循环)。又或者是t1拿到一个数据库锁,释放锁的时候抛出了异常,没释放掉。
一旦出业务是可感知的,因不能继续提供服了,那么只能通dump线看到底是哪个线程出问题
在我避免死的几个常方法。
 
·避免一个线程同时获取多个
 
·避免一个线程在内同占用多个源,尽量保每个只占用一个源。
 
·尝试使用定时锁,使用lock.tryLocktimeout)来替代使用内部机制。
 
·于数据库锁,加和解在一个数据库连接里,否会出的情况。

1.3 源限制的挑

(1)什么是源限制

源限制是指在行并发编,程序的行速度受限于算机硬件源或资源。例如,服务器的带宽只有2Mb/s,某个资源的下载速度是1Mb/s每秒,系统启动10个线程下载资源,下载速度不会变成10Mb/s,所以在进行并发编程时,要考虑这些资源的限制。硬件资源限制有带宽的上传/下载速度、硬盘读写速度和CPU的处理速度。软件资源限制有数据库的连接数和socket连接数等
 
2源限制引问题
在并发编程中,将代码执行速度加快的原是将代中串行行的部分成并发执行, 但是如果将某段串行的代码并发执行,因为受限于资源,仍然在串行执行,这时候程序不仅不会加快执行,反而会更慢,因为增加了上下文切换和资源调度的时间。
 
3)如何解决源限制的问题
对于硬件资源限制,可以考虑使用集群并行执行程序。既然机的源有限制,那么就让程序在多机上运行。比如使用ODPSHadoop或者自己搭建服器集群,不同的机器理不同的数据。可以通过数据ID%机器数算得到一个机器号,然后由对应编号的机器这笔数据。对于软件资源限制,可以考虑使用资源池将资源复用。比如使用接池将数据Socket连接复用,或者在webservice接口取数据,只建立一个接。
 
4)在源限制情况下行并发编如何在源限制的情况下,程序行得更快呢?方法就是,根据不同的资源限制调整程序的并发度,比如下文件程序依于两个——带宽和硬盘读写速度。有数据操作 时,涉及数据库连接数,如果SQL行非常快,而线程的数量比数据库连接数大很多,则某些线程会被阻塞,等待数据库连接。

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值