并发编程(一)

一、小结

  1. 串行和并行

    串行:一个线程在处理操作 

    并行:多个线程在处理同一个操作

  2. 什么叫并发编程:再多线程环境下,应用程序的执行

  3. 并发编程 的目的:充分运用到资源,提高程序的效率

  4. 什么情况下用到并发编程 :

          4.1 在线程阻塞时,导致应用程序停止

          4.2 处理任务时间过长时2,可以创建子任务,来进行分段处理

          4.3 见端倪任务执行

二、并发编程中待解决的问题

  1. 并发编程中频繁上下文切换问题

    频繁上下文切换,可能会带来一定的性能开销

    如何减少上下文性能开销:

            1.无锁编程

            2.CAS:Compare and Swap,是比较并交换的意思

            3. 使用最少线程数量

            4. 协程:在单线程环境下进行多任务调度,而一再多任务之间进行交换

  2. 并发编程中死锁问题

    多个线程在抢占资源,但是抢占过程当中资源如果被占用,会造成阻塞,如果多个线程互抢资源时,就会造成死锁情况,死锁会导致应用程序的阻塞

  编写测试代码

public class DeadLockTest {
    private static final Object  HAIR_A=new Object();
    private static final Object  HAIR_B=new Object();

    public static void main(String[] args) {
        //第一个人
        new Thread(()->{
            //护住自己的头发
            synchronized (HAIR_A){
                System.out.println("第一个人护住自己的头发,准备抢第二个人的头发");
                //延时时间
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //薅第二个人的头发
                synchronized (HAIR_B){
                    System.out.println("第一个人薅到了的第二个人的头发");
                }
            }

        }).start();
        //第二个人
        new Thread(()->{
            //护住自己的头发
            synchronized (HAIR_B){
                System.out.println("第二个人护住自己的头发,准备抢第一个人的头发");
                //延时时间
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //薅第二个人的头发
                synchronized (HAIR_A){
                    System.out.println("第二个人薅到了的第一个人的头发");
                }
            }

        }).start();
    }
}

  控制台效果

  命令窗口

  如何防止死锁问题

    1. 破坏请求和保持条件:在申请资源时,一次性将资源都申请到

    2. 破坏不可占用资源:抢占资源如何不满足,那就释放所有资源,以如果在需要则再次申请即可

    3. 破坏循环等待条件

  3. 线程安全问题

    多个线程同时操作同一个资源,可能会造成资源数据不安全问题

  编写 示例代码

  private static int  num=0;
    //计算线程数量
    private static CountDownLatch countDownLatch=new CountDownLatch(10);
    //对资源进行操作
    public static void inCreate(){
        num++;
    }

    public static void main(String[] args) throws InterruptedException {
        for (int i=0;i<10;i++){
            new Thread(()->{
                for (int j=0;j<100;j++){
                    inCreate();
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //每一个 线程执行完毕,让计数减一
                countDownLatch.countDown();
            }).start();

        }
        //等待计数器为0或者小0执行await下面代码
        countDownLatch.await();
        System.out.println(num);
    }

  解决方案一:

 private static int  num=0;
    //计算线程数量
    private static CountDownLatch countDownLatch=new CountDownLatch(10);
    //对资源进行操作
    public static  void inCreate(){
        synchronized (UnsafeThread.class){
            num++;
        }

    }

    public static void main(String[] args) throws InterruptedException {
        for (int i=0;i<10;i++){
            new Thread(()->{
                for (int j=0;j<100;j++){
                    inCreate();
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //每一个 线程执行完毕,让计数减一
                countDownLatch.countDown();
            }).start();

        }
        //等待计数器为0或者小0执行await下面代码
        countDownLatch.await();
        System.out.println(num);
    }
原文地址:https://www.cnblogs.com/szhhhh/p/12518219.html