Java多线程:平面和跑道案例研究的例子

时间:2016-04-26 17:31:38

标签: java multithreading concurrency

所以大家好,我实际上是新编码的,即使是基本编码也存在很多问题。

所以我的讲师给出了这个案例研究:模拟一次可以容纳1架飞机降落的飞机和4条跑道的数量。如果所有4条跑道都被占用,其他飞机必须等待其中一条或多条跑道起飞。对我来说很难,所以我首先尝试使用2条跑道和4架飞机。

Plane是线程类,Runway是普通类。到目前为止我做了什么:

  1. 主类

       public class Main {
            public static void main(String[] args) {
                Runway r[] = new Runway[2];
                for (int i = 0; i < r.length; i++) {
                    r[i] = new Runway(i);
                }
    
                Plane p[] = new Plane[4];
    
                for (int i = 0; i < p.length; i++){
                    p[i] = new Plane(i, r[0], r[1]);
                    p[i].start();
                }
            }
        }
    
  2. 跑道班

        public class Runway {
            private int id;
            private Lock l;
            public boolean available = true;
    
            public Runway(int id){
                this.id = id;
                l = new ReentrantLock();
            }
    
            public boolean landing(int idp){
                boolean i;
                i = l.tryLock();
                if (i == true) {
                    available = false;
                    System.out.println("Plane " + idp + " is landing on Runway: " + id);
                }
                return i;
            }
    
            public void takeOff(int idp){
                System.out.println("Plane " + idp + " is take off from Runway: " + id);
                available = true;
                l.unlock();
            }
        }
    
  3. 平面类

        public class Plane extends Thread {
            private Runway r1, r2;
            private int id, tag;
            private boolean i = false;
    
            public Plane(int id, Runway r1, Runway r2){
                this.id = id;
                this.r1 = r1;
                this.r2 = r2;
            }
    
            public void run(){
                if (i == false) {
                    if (r1.available == true) {
                        i = r1.landing(id);
                        tag = 1;
                    } else if (r2.available == true) {
                        i = r2.landing(id);
                        tag = 2;
                    }
                }
    
                sleep();
    
                if (tag == 1 & i == true){
                    r1.takeOff(id);
                    i = false;
                } else if (tag == 2 & i == true) {
                    r2.takeOff(id);
                    i = false;
                }
            }
    
            private void sleep(){
                try {
                    Thread.sleep(new Random().nextInt(8)*100);
                }catch (Exception e){}
            }
        }
    
  4. 这是结果......

    Plane 1 is landing on Runway: 0
    Plane 3 is landing on Runway: 1
    Plane 1 is take off from Runway: 0
    Plane 3 is take off from Runway: 1
    
    Process finished with exit code 0
    

    并非所有飞机都着陆,我知道这是基本的,但任何帮助都表示赞赏:D

2 个答案:

答案 0 :(得分:0)

这是一种替代同步访问共享状态的方法。将变量标记为易失性是一个简单的&#39;替代同步,具有较少的运行时开销。它告诉JVM内存管理器保证&#39;活跃度&#39;变量到所有访问线程

修改

  • 在我意识到volatile关键字无法保证试图降落飞机的操作原因之后,我做了一些修改。
  • 我也意识到在构造之后永远不会修改id,因此不需要volatile关键字

import java.util。*;     import java.util.concurrent.atomic.AtomicReference;

public class Airport {

    /**
     * if number of planes is less than or equal to twice the number of runways
     * the execution will terminate ie all planes that want to land
     * will land and all those that wish to take off will take off .
     * Otherwise there wont be enough runways for the landing planes and the execution will
     * go on indefinitely .
     */
    static Runway r[] = new Runway[10];
    static Plane p[] = new Plane[20];

    public static void main(String[] args) {
        //instantiate array of planes
        for (int i = 0; i < p.length; i++){
            p[i] = new Plane(i);
        }

        //instantiate runways and allocate planes to runways
        List<Plane> planes = Arrays.asList(p);
        Iterator<Plane> iterator;
        Collections.shuffle(planes);
        iterator= planes.iterator();
        for (int i = 0; i < r.length; i++) {
            Plane p;
            try {
                p= iterator.next();
            }catch ( RuntimeException e){
                p= null;
            }
            r[i] = new Runway(i,p);
        }

        //display initial state
        for (int i = 0; i < p.length; i++){
            Runway runway=getUsedRunway(p[i]);
            System.out.println("plane "+p[i].id + " is "+(runway==null?"waiting to land":("on runway "+runway.id)));
        }

        System.out.println("======== Begin! ============");

        //let the games begin
        for (int i = 0; i < p.length; i++){
            p[i].start();
        }
    }


    private static class Runway {
        //only ever read after construction . no need for special handling for concurreny
        private int id;

        /**
         * volatile keyword gives atomic read and atomic write operation in isolation .
         * However to land the plane we need to set the runway's plane reference value based on its current value .
         * This scenario is called out specifically by B Goetz in this article https://www.ibm.com/developerworks/java/library/j-jtp06197/
         * ( and in his book Javas one in which volatile is insufficient for thread safety
         * We need an atomic compare and set
         */
        private AtomicReference<Plane> planeAtomicReference;

        public Runway(int i, Plane p) {
            id =i;
            planeAtomicReference = new AtomicReference<>();
            planeAtomicReference.set(p);
        }
    }


    private static class Plane extends Thread {
        //only ever read after construction . no need for special handling for concurreny
        private int id;

        Plane(int i){
            id=i;
        }

        @Override
        public void run() {
            Runway runway=getUsedRunway(this);
            if(runway==null){
                System.out.println("plane "+id+" wants to land");
                Runway availableRunway = getAvailableRunway();
                while ((availableRunway=atomicallyAttempToLandPlane(this))==null) {
                    System.out.println("no runway available yet for plane " + id);
                    try {
                        sleep(30);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("landed plane "+id+" on runway "+availableRunway.id);
            }else {
                System.out.println("plane "+id+" wants to take off from runway "+runway.id);
                runway.planeAtomicReference.set(null);
                System.out.println("plane "+id+" has taken off from runway ");
            }
        }

        /**
         *
         * @param plane
         * @return
         */
        private Runway atomicallyAttempToLandPlane(Plane plane) {
            for (int i = 0; i < r.length; i++) {
                if(r[i].planeAtomicReference.compareAndSet(null,plane)){
                    return r[i];
                }
            }
            return null;
        }
    }

    /**
     *  does not require synchronization since the size of the arrays is fixed during execution and the elements
     *  to which they refer is also fixed .  only the internal state of elements themselves is open to change
     *  and that has been guaranteed  by marking it as volatile as well as additional atomic behaviour
     * @return
     */
    private static Runway getAvailableRunway(){
        for (int i = 0; i < r.length; i++) {
            if(r[i].planeAtomicReference.get() ==null){
                return r[i];
            }
        }
        return null;
    }



    /**
     *  does not require synchronization since the size of the arrays is fixed during execution and the elements
     *  to which they refer is also fixed .  only the internal state of elements themselves is open to change
     *  and that has been guaranteed  by marking it as volatile as well as additional atomic behaviour
     * @param plane
     * @return
     */
    private static Runway getUsedRunway(Plane plane){
        for (int i = 0; i < r.length; i++) {
            final Plane planeOnRunway  = r[i].planeAtomicReference.get();
            if(planeOnRunway !=null && planeOnRunway.id==plane.id){
                return r[i];
            }
        }
        return null;
    }


}

答案 1 :(得分:0)

通过将飞机视为线程,将跑道数视为信号灯中的锁数来解决此问题。

然后代码将如下所示:

public class Runway {

  Semaphore semaphore = new Semaphore(4);

  public void landThePlane() {

    try {
        semaphore.acquire();
        // code to land the plane
        System.out.println("The plane is landing");
        Thread.sleep(3000); // just to show you in the console that the next 4 
                            // threads will be executed afterwards - not imp 
        semaphore.release();

    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

public static void main(String[] args) {

    Runway runway = new Runway();
    ExecutorService executorService = Executors.newFixedThreadPool(10);
    for (int i = 0; i < 10; i++) {
        executorService.execute(() -> runway.landThePlane());
    }
}

}