容量等于N的滑雪缆车。

时间:2017-06-15 14:43:35

标签: java multithreading

我正在学习多线程。这是我的第一个任务。我写了这段代码,我无法继续前进。任务:

容量相等的滑雪缆车N. 客户端具有权重(随机Ki值),它们是执行的线程 循环:

  1. 下坡(睡觉(大随机值)
  2. 尝试进入电梯(如果客户的总重量是 小于或等于N)。
  3. 如果失败 - 他们正在等待(睡眠(小随机值) 并重新执行前一点。
  4. 如果成功了 - 他们会上去。

    public class Client extends Thread
     {
        private SkiLift lift;
        private int weight;

    public Client(SkiLift l, int w)
    {
        this.lift = l;
        this.weight=w;
    }
    
    public int getWeight()
    {
        return weight;
    }
    
    public void run()
    {
        for (int i =0; i<10; i++)
        {
            lift.downhill(this);
            lift.goIn(this);
            this.setPriority(MAX_PRIORITY);
            lift.drive(this);
            lift.goOut(this);
            this.setPriority(5);
        }
    }
    

    } public class SkiLift { private static int actualLoad=0; private static final int CAPACITY=300;

    synchronized public void goIn(Client client) { try { System.out.println("Client " + client.getId() + " try to get into the lift"); while (actualLoad>CAPACITY) { System.out.println("The Lift is full!"); client.sleep((long) (Math.random()*1000)); wait(); } } catch (InterruptedException e) {} System.out.println("Client " + client.getId() + "get into the lift " ); actualLoad+=client.getWeight(); System.out.println("actual load = " + actualLoad); } synchronized public void goOut (Client client) { System.out.println("Client "+ client.getId() + " leave the lift "); actualLoad-=client.getWeight(); System.out.println("Actual load = " + actualLoad); notifyAll(); } public void downhill(Client client) { System.out.println("Client nr: " + client.getId()+ " downhill "); try { client.sleep((long) (Math.random()*10000)); } catch (InterruptedException e){} } public void drive(Client client) { try { client.sleep(9000); } catch (InterruptedException e){e.printStackTrace();} }

    }

  5. 我有三个问题,我无法解决它们:

    1. 第一个进入的人必须是第一个试图进入的人。 (就像在队列中一样)
    2. 首次乘坐电梯的客户也必须是第一个下楼的客户。
    3. 我的节目中的moniotor是什么?
    4. 提前致谢:)

2 个答案:

答案 0 :(得分:0)

显然,系统中的瓶颈是电梯。电梯只能有N个并发用户。

另外,3。提到了一个监视器。在阅读了显示器的内容之后,您应该弄清楚它允许独占访问有限的资源,即电梯。

因此,设计您的电梯访问权限以尝试获取N个显示器中的一个,等待一段时间,最后不要忘记释放显示器,以便其他人可以获得它。

答案 1 :(得分:0)

我认为这个问题属于Codereview

您的客户应该拥有“topOfTheMountainReached”,“liftStationReached”,“liftEntered”等状态......

您的客户等待此事件发生。这也是你的问题的答案,要监控哪个元素 - 国家或客户本身。

对于队列,您可以使用ArrayListBlockingQueue。 然后,您的SkiLift必须等待新客户到达并将其放入电梯。一旦客户进入电梯,客户也会收到通知它已进入电梯的通知。当达到顶部时,Lift还会通知客户端。

以下是此类解决方案的外观示例。 它使用Java Executor服务来安排事件,使客户端离开电梯,并在下坡部分的末端到达电梯站。这也可以用不同的方式解决。

客户:

import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class Client implements Runnable{

    final ScheduledExecutorService dhexceutors = Executors.newScheduledThreadPool(500);

    final static Random DHRANDOM = new Random();

    final long weight;

    public enum State {
        goDownhill,
        waitForLift,
        goUp,
        onTop,
    }

    private State state;

    public SkiLift lift; 

    public Client(long weight,SkiLift lift) {
        this.lift = lift;
        this.weight = weight;
        this.state = State.onTop;
        goDownHill();
    }

    private void enterLift() {
        lift.add(this);
    }


    private void goDownHill() {
        synchronized (this) {
            state = State.goDownhill;
            this.notify();
        }
        dhexceutors.schedule(() -> {
            liftStationReached();
        }, DHRANDOM.nextInt(500), TimeUnit.MILLISECONDS); 
    }

    public void liftStationReached() {
        synchronized(this) {
            state = State.waitForLift;
            this.notify();
        }
    }


    public void topReached() {
        synchronized(this) {
            state = State.onTop;
            this.notify();
        }
    }

    public void liftEntered() {
        synchronized(this) {
            state = State.goUp;
            this.notify();
        }
    }


    public void run() {
        synchronized(this) {
            while (true) {
                try {
                    this.wait();

                    switch (state) {
                    case waitForLift:
                        enterLift();
                        break;
                    case goUp: 
                        // just wait for the topReached event
                        break;
                    case goDownhill:
                        // just wait for reaching the lift.
                        break;
                    case onTop: 
                        goDownHill();
                        break;
                    }

                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                }
            }
        }
    }

}

电梯:

package skilift;

import java.util.ArrayList;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class SkiLift implements Runnable{

    private ScheduledExecutorService getOutClientExecutor;

    public SkiLift() {
        getOutClientExecutor = Executors.newScheduledThreadPool(50);
        waitingClientsQueue = new ArrayBlockingQueue<>(1000);
        occupiedSeats = new ArrayList<>();
    }

    private final ArrayList<Client> occupiedSeats; 

    private long usedCapacity;

    private final ArrayBlockingQueue<Client> waitingClientsQueue;

    private final long capacity = 500;

    public void add(Client client) {
        synchronized(waitingClientsQueue) {
            waitingClientsQueue.add(client);
            waitingClientsQueue.notify();
        }

    }


    private synchronized void occupySeat(Client client) {
        occupiedSeats.add(client);
        usedCapacity += client.weight;
    }

    private synchronized void getClientOut(Client client) {
        occupiedSeats.remove(client);
        usedCapacity -= client.weight;

        // notify the waitingClientQueue that the capacity has changed
        synchronized (waitingClientsQueue) {
            waitingClientsQueue.notify();
        }

        client.topReached();
    }


    public void run() {
        while (true) {
            synchronized(waitingClientsQueue) {
                try {

                    if (!waitingClientsQueue.isEmpty()) {
                        Client c = waitingClientsQueue.peek();
                        if (usedCapacity + c.weight <= capacity) {
                            occupySeat(waitingClientsQueue.poll());
                            getOutClientExecutor.schedule(() -> {
                                getClientOut(c);
                            }, 2, TimeUnit.SECONDS);
                        } else {
                            waitingClientsQueue.wait();
                        }
                    } else {
                        waitingClientsQueue.wait();
                    }

                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                }
            }
        }
    }

}