并发编程介绍


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

 什么叫做并发编程:

   在多线程环境下,应用程序的执行

 并发编程的目的:

     充分运用到资源,提高程序的效率

  什么情况下用到并发编程:
            1.在线程阻塞时,导致应用程序停止
            2.处理任务时间过长时,可以创建子任务,来进行分段处理
            3.间断任务执行
            
        
        一.并发编程中待解决的问题
            1.并发编程中频繁上下文切换的问题
                频繁上下文切换,可能会带来一定的性能开销
                如何减少上下文性能开销:
                    1.无锁并发编程
                    2.CAS
                    3.使用最少线程数量
                    4.协程:在单线程环境下进行多任务的调度,可以在多任务之间进行任务切换
            
            
            2.并发编程中死锁问题
                多个线程在抢占资源,但是抢占过程当中资源如果被占用,会造成阻塞,如果多个线程互抢资源时,就会造成死锁情况,死锁会导致应用程序的阻塞
                
                案例:    

                    public class DeadLockDemo {
                        //资源
                        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);      //当前线程休眠,让渡CPU资源
                                    } catch (InterruptedException e) {
                                        e.printStackTrace();
                                    }
                                    //薅第一个人的头发
                                    synchronized (HAIR_A){
                                        System.out.println("第二个人薅到了第一个人的头发");
                                    }
                                }
                            }).start();
                        }
                    }

 

 

 jconsole查看死锁详细信息

 

 

 

 

 

 


                如何预防死锁问题:
                    1.破坏请求和保持条件:在申请资源时,一次性将资源都申请到 (尽量在同一个代码块请求资源)
                    2.破坏不可占用条件:抢占资源如何不满足,那就释放所有资源,以后如果再需要则再次申请即可(不一直占用资源,没有申请到资源就先释放再申请)
                    3.破坏循环等待条件(指定执行顺序)
                    
            3.线程安全问题
                多个线程同时操作同一个资源,可能会造成资源数据不安全问题
                
                示例:
                  

            public class UnsafeThread {
                        //资源
                        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(100);
                                        } catch (InterruptedException e) {
                                            e.printStackTrace();
                                        }
                                    }
                                    //每一个线程执行完毕,让计数-1
                                    countDownLatch.countDown();
                                }).start();
                            }
                            //等待计数器为0或者小于0执行await下面代码
                            countDownLatch.await();
                            System.out.println(num);
                        }
                    }

多次执行效果都不一致,都与预期值不符

 

 

 

 

 

 


                解决线程不安全问题:

public class SafeThread {
        //资源
        private static int num=0;
        //计算线程数量
        private static CountDownLatch countDownLatch=new CountDownLatch(10);
        private static ReentrantLock reentrantLock = new ReentrantLock();

        //对资源进行操作
        public static synchronized void inCreate(){
            //上锁
            num++;
        }
        
        /*public static synchronized void inCreate(){
            //上锁
            synchronized(SafeThread.class){
                num++;
            }
        }*/

        /*public static void inCreate(){
            //上锁
            reentrantLock.lock();
            num++;
            reentrantLock.unlock();
        }*/


        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(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    //每一个线程执行完毕,让计数-1
                    countDownLatch.countDown();
                }).start();

            }
            //等待计数器为0或者小于0执行await下面代码
            countDownLatch.await();
            //获取到当前计数器中的线程数量
                            /*while (true){
                                if(countDownLatch.getCount()<=5){
                                    System.out.println(num);
                                    break;
                                }
                            }*/
            System.out.println(num);


        }

}

 

得到预期值

 

posted @ 2020-03-18 17:15  怀鑫  阅读(224)  评论(0编辑  收藏  举报