zoukankan      html  css  js  c++  java
  • 线程安全以及死锁问题

    死锁

    死锁是指多个线程运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进。

    产生死锁的四个必要条

    1. 互斥条件:进程要求对所分配的资源进行排它性控制,即在一段时间内某资源仅为一进程所占用。
    2. 请求和保持条件:当进程因请求资源而阻塞时,对已获得的资源保持不放。
    3. 不剥夺条件:进程已获得的资源在未使用完之前,不能剥夺,只能在使用完时由自己释放。
    4. 环路等待条件:在发生死锁时,必然存在一个进程--资源的环形链。

    编写产生死锁的代码

    复制代码
    public class TestDeadLock {
        private static Object obj1 = new Object();
        private static Object obj2 = new Object();
    
        public static void main(String[] args) {
            new Thread(new Thread1()).start();
            new Thread(new Thread2()).start();
        }
    
        private static class Thread1 implements Runnable {
            @Override
            public void run() {
                synchronized (obj1) {
                    System.out.println("Thread1 拿到了 obj1 的锁!");
                    try {
                    // 停顿2秒的意义在于,让Thread2线程拿到obj2的锁
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (obj2) {
                        System.out.println("Thread1 拿到了 obj2 的锁!");
                    }
                }
            }
        }
    
        private static class Thread2 implements Runnable {
            @Override
            public void run() {
                synchronized (obj2) {
                    System.out.println("Thread2 拿到了 obj2 的锁!");
                    try {
                    // 停顿2秒的意义在于,让Thread1线程拿到obj1的锁
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (obj1) {
                        System.out.println("Thread2 拿到了 obj1 的锁!");
                    }
                }
            }
        }
    
    }
    复制代码

    使用jstack加上进程号进行查看

    预防死锁:

    1. 资源一次性分配:一次性分配所有资源,这样就不会再有请求了:(破坏请求条件)
    2. 只要有一个资源得不到分配,也不给这个进程分配其他的资源:(破坏请保持条件)
    3. 可剥夺资源:即当某进程获得了部分资源,但得不到其它资源,则释放已占有的资源(破坏不可剥夺条件)
    4. 资源有序分配法:系统给每类资源赋予一个编号,每一个进程按编号递增的顺序请求资源,释放则相反(破坏环路等待条件)

    线程安全

    模拟线程不安全代码

    复制代码
    public class Test {
        private static Integer count=0;
        public  static void add(){
            count++;
        }
       static CountDownLatch downLatch=new CountDownLatch(100);
        public static void main(String[] args) throws InterruptedException {
    
            for (int i = 0; i <100 ; i++) {
    
                new Thread(()->{
                    for (int j = 0; j <10 ; j++) {
                        add();
                    }
                    downLatch.countDown();
                }).start();
    
            }
            downLatch.await();
            System.out.println(count);
    
        }
    }
    复制代码

    解决方案

    1:添加synchronized

    复制代码
    public class Test {
        private static Integer count=0;
        public synchronized  static void add(){
            count++;
        }
       static CountDownLatch downLatch=new CountDownLatch(100);
        public static void main(String[] args) throws InterruptedException {
    
            for (int i = 0; i <100 ; i++) {
    
                new Thread(()->{
                    for (int j = 0; j <10 ; j++) {
                        add();
                    }
                    downLatch.countDown();
                }).start();
    
            }
            downLatch.await();
            System.out.println(count);
    
        }
    }
    复制代码

    2.加lock锁

    复制代码
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class Test {
        private static Integer count = 0;
    
        public  static void add() {
            try {
                reentrantLock.lock();
                count++;
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                reentrantLock.unlock();
            }
    
    
        }
    
        static ReentrantLock reentrantLock = new ReentrantLock();
        static CountDownLatch downLatch = new CountDownLatch(100);
    
        public static void main(String[] args) throws InterruptedException {
    
            for (int i = 0; i < 100; i++) {
    
                new Thread(() -> {
                    for (int j = 0; j < 10; j++) {
                        add();
                    }
                    downLatch.countDown();
                }).start();
    
            }
            downLatch.await();
            System.out.println(count);
    
        }
    }
    复制代码

    3.上面的这种情况还可以使用原子类

    复制代码
    package test;
    
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.atomic.AtomicInteger;
    
    public class Test {
        private static AtomicInteger count = new AtomicInteger(0);
    
        public  static void add() {
            count.incrementAndGet();
        }
    
        static CountDownLatch downLatch = new CountDownLatch(100);
    
        public static void main(String[] args) throws InterruptedException {
    
            for (int i = 0; i < 100; i++) {
    
       
  • 相关阅读:
    Windows Server 2003 SP2(32位) 中文版 下载地址 光盘整合方法
    用Recycle()方法对Java对象的重要性
    Lotus中千奇百怪的 $$
    Developing a simple application using steps "User Decision" and "Mail"(1) 沧海
    沟通中的情绪管理(演讲稿) 沧海
    人只有在压力之下,才可能成功,没做一件事,都必须成功,不许言败 沧海
    什么是IDOC,以及IDOC的步骤 沧海
    VS2008 Professional Edition CHS中的deffactory.dat读取错误 沧海
    Including custom text in the step "User Decision" 沧海
    SAP Upgrade Strategy 沧海
  • 原文地址:https://www.cnblogs.com/wangdayexinyue/p/12521341.html
Copyright © 2011-2022 走看看