美文网首页
10章 - 多线程并发扩展

10章 - 多线程并发扩展

作者: 菜鸟程序员一枚 | 来源:发表于2019-02-22 12:23 被阅读8次

    死锁 - 必要条件

    互斥条件:进程要求对所分配的资源(如打印机)进行排他性控制,即在一段时间内某资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待。
    请求和保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。
    不剥夺条件:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能由获得该资源的进程自己来释放(只能是主动释放)。
    环路等待条件:存在一种进程资源的循环等待链,链中每一个进程已获得的资源同时被链中下一个进程所请求。即存在一个处于等待状态的进程集合{Pl, P2, ..., pn},其中Pi等 待的资源被P(i+1)占有(i=0, 1, ..., n-1),Pn等待的资源被P0占有,如图1所示。

    代码演示:

    /**
     * 一个简单的死锁类
     * 当DeadLock类的对象flag==1时(td1),先锁定o1,睡眠500毫秒
     * 而td1在睡眠的时候另一个flag==0的对象(td2)线程启动,先锁定o2,睡眠500毫秒
     * td1睡眠结束后需要锁定o2才能继续执行,而此时o2已被td2锁定;
     * td2睡眠结束后需要锁定o1才能继续执行,而此时o1已被td1锁定;
     * td1、td2相互等待,都需要得到对方锁定的资源才能继续执行,从而死锁。
     */
    
    @Slf4j
    public class DeadLock implements Runnable {
        public int flag = 1;
        //静态对象是类的所有对象共享的
        private static Object o1 = new Object(), o2 = new Object();
    
        @Override
        public void run() {
            log.info("flag:{}", flag);
            if (flag == 1) {
                synchronized (o1) {
                    try {
                        Thread.sleep(500);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    synchronized (o2) {
                        log.info("1");
                    }
                }
            }
            if (flag == 0) {
                synchronized (o2) {
                    try {
                        Thread.sleep(500);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    synchronized (o1) {
                        log.info("0");
                    }
                }
            }
        }
    
        public static void main(String[] args) {
            DeadLock td1 = new DeadLock();
            DeadLock td2 = new DeadLock();
            td1.flag = 1;
            td2.flag = 0;
            //td1,td2都处于可执行状态,但JVM线程调度先执行哪个线程是不确定的。
            //td2的run()可能在td1的run()之前运行
            new Thread(td1).start();
            new Thread(td2).start();
        }
    }
    
    

    多线程并发最佳实践

    使用本地变量
    使用不可变类
    最小化锁的作用于范围:S=1/(1-a+a/n)
    使用线程池的Executor,而不是直接new Thread执行
    宁可使用同步也不要使用线程的wait和notify
    使用BlockingQueue实现生产-消费模式
    使用并发集合而不是加了锁的同步集合
    使用Semaphore创建有界的访问
    宁可使用同步代码块,也不要使用同步的方法
    避免使用静态变量

    相关文章

      网友评论

          本文标题:10章 - 多线程并发扩展

          本文链接:https://www.haomeiwen.com/subject/yygqsqtx.html