OOUnitTwo

目录

  • 一、关于多部可捎带可换乘电梯优化
  • 二、奇奇妙妙的Bug们
  • 三、关于死锁

一、优化

  • 配合Look调度食用
  • 在换乘方面没啥可说的,事实证明我的方法没有打表好。
  • 具体电梯分配策略:每个电梯都拥有两个队列,requestlist(外部还没上电梯的等待队列,后面简称为rlist),innerlist(电梯内部已经上来了的请求队列,后面简称ilst)。每个电梯都拥有一个ElevatorStatus对象,对象被相应电梯线程和输入线程所共有。ElevatorStatus对象拥有direction、currentfloor、elevatorname、elevatortype、passagernumber的属性,拥有get和set方法。电梯线程实时更新status信息。
  • 调度器中拥有getNum()方法,用来获得如果电梯待处理的请求数量(更细致的说是如果新请求上了此电梯时,电梯还要处理的请求数量)。具体操作:先检查电梯ilist队列,如果电梯在向上走并且队列里请求的到达楼层>新请求r的起始楼层,则说明在r进入电梯时此请求还没有下电梯,电梯还得继续处理它,所以将num++,电梯向下走同理。再检查rlist队列,以电梯向上走为例,如果rlist队列里面的请求的起始楼层大于现在的楼层,并且这个请求也是向上走,并且在新请求进电梯时他还没有出去,说明这个请求在新请求进电梯时,也在电梯里,并且还没被处理完,因此将num++,向下走同理。
  • 调度器中还拥有getSize()方法,用以获得一个电梯rlist和ilist中请求数总和。
  • 总体思想:实时获得电梯状态,在获得一个新请求后,先查找能够顺路将它接上并且任务数最少的电梯,顺路是指比如电梯向上走,请求在电梯上面并且请求也是向上走的(查找任务数使用getNum()方法,其所需电梯状态从ElevatorStatus中获得),并将其塞进电梯的rlist里;如果没有,查找总任务数最少的电梯(查找总任务数使用getSize()方法,其所需电梯状态从ElevatorStatus中获得),并将其塞进电梯的rlist里。
  • 但是对于换乘请求的后半部分,我在把它拆出来后即放入一个secondlist的大队列中,在其前半部分执行完后,再将其从secondlist中取出,通过以上的分配策略,将其扔进相应的电梯队列里。通过这种方法,可以尽量去减少因开关门而导致的电梯内人的时间的增多。
  • 小trick:一开门就下人,临关门再上人。可以使人在电梯里的时间少一点,并且每次电梯捞上更多的人。

二、奇妙Bug们

结束线程的Bug:

第五次作业:我是设了一个isend标志,然后结束的时候如果isend并且请求队列为空,那么就结束。但是没结束的时候,我会去判请求队列是不是空,如果是空就wait住。就像下面这样。

 while (requestList.isEmpty()) {
     try {
         wait();
     } catch (InterruptedException e) {
         e.printStackTrace();
     }
 }

但是这又一个很致命的问题,就是如果你在跑完所有请求再ctrlD(将isend置位),电梯线程就有可能没办法停下来。因为那时候请求队列已经empty了,即使wait被唤醒,也跳不出while循环。
解决方法:在while循环中加一个特判:如果isend被置位并且请求队列空了,就强制退出循环,并返回循环结束的标志。

暴力轮询的Bug:

第七次作业:在while循环中,为了得到换乘请求后半部分的状态,调用了一个方法,然而此方法会在while循环中一直不停的被调用获取,导致cpu时间爆涨。
解决方法:善用wait和notifyall(或await+signalall)保险起见,可以在在while循环中干了任何事儿后,都打印一下能代表它发生了的特殊的标志,看看会不会停不下来。

三、死锁知识总结

死锁活锁和死等的定义与区别

在这里插入图片描述

死锁产生的必要条件:

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

相应破解:

1.资源一次性分配:在进程线程运行之前,就把需要申请的资源一次性申请到位,满足则运行,不满足就等待,这样就不会造成在占有资源的情况下,还要申请新资源(破坏请求条件)
2.可剥夺资源:即当某线程获得了部分资源,但得不到其它资源,则释放已占有的资源(破坏不可剥夺条件)
3.资源有序分配法:系统给每类资源赋予一个编号(比如相应对象的hashcode),每一个线程按编号定一个相同的特定顺序请求资源,释放则相反(破坏环路等待条件)

经典算法(银行家算法):

银行家算法链接

超时放弃:

当使用synchronized关键词提供的内置锁时,只要线程没有获得锁,那么就会永远等待下去。可以加一个超时时间,若一个线程没有在给定的时限内成功获得所有需要的锁,则会进行回退并释放所有已经获得的锁,然后等待一段随机的时间再重试。应用ReentrantLock里的boolean tryLock(long time, TimeUnit unit) throws InterruptedException方法
示意如下,tryLockInterruptThread如果等了1000ms还抢不到锁,就放弃对锁的请求。

TestLockAndTryLock lockAndTryLock = new TestLockAndTryLock();
Thread tryLockInterruptThread = new Thread(
                () -> lockAndTryLock.tryLockInterruptTest(), "TryLockInterrupt-Thread"
        );
	private void tryLockInterruptTest(){

        long currentTime = System.currentTimeMillis();

        while (System.currentTimeMillis() - currentTime <= 100){
            //assume do something
        }

        try {
            System.out.println("Begin time: " + System.currentTimeMillis());
            if (rlock.tryLock(1000, TimeUnit.MILLISECONDS)){
                try {
                    System.out.println("tryLockInterruptTest----current thread get the lock: " + Thread.currentThread().getName());

                }finally {
                    rlock.unlock();
                    System.out.println("tryLockInterruptTest----current thread release the lock: " + Thread.currentThread().getName());
                }

            }else {
                System.out.println("End time: " + System.currentTimeMillis());
                System.out.println("tryLockInterruptTest----current thread CAN NOT get the lock: " + Thread.currentThread().getName());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

   
死锁检测:

jstack:jstack可以用于生成java虚拟机当前时刻的线程快照,从而定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。 线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。
操作:通过jps获得当前进程号,执行jstack -e 进程号操作查看当前进程堆栈信息。
结果如下:在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值