CountDownLatch模拟田径赛跑

群里得一面试题,正好用来练手

现有一场田径比赛,共有8个选手参赛。他们编号分别为: A,B,C,D,E,F,G,H; 赛事观察员分别在开始后 20s和30s拍下两张照片,各个选手的排名情况如下, 20s:F,A,H,G,C,B,E,D;30s:G,H,A,C,F,D,B,E;请你写出一个程序, 模拟出这些参赛选手在20-30s这10s的内排名变化,每1s显示一次排名。

主要是考察countDownLatch。
计算的时候clone出快照。避免计算的过程中瞬间值又有变化,导致算出的值不准确。

拍照也就是存一下快照而已。
ps:可能是对题理解有误,下面的效果不追求固定名次。
固定名次的写法思路是:写死 各个选手在20s的时候的距离(a),根据a减去各个选手当前的距离(0),然后再 随机到每一秒,就是选手每秒的跑的距离。 30s 的时候重新定义一下目标距离(b),b减去选手的20s时候的距离a,随机到每一秒。

效果

代码

package com.gkwind.concurrent;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;


/**
 * 现有一场田径比赛,共有8个选手参赛。他们编号分别为: A,B,C,D,E,F,G,H;
 * 赛事观察员分别在开始后   20s和30s拍下两张照片,各个选手的排名情况如下,
 * 20s:F,A,H,G,C,B,E,D;30s:G,H,A,C,F,D,B,E;请你写出一个程序,
 * 模拟出这些参赛选手在20-30s这10s的内排名变化,每1s显示一次排名。
 *
 * @Author thewindkee
 * @Date 2019/7/18 0018  22:36
 */
public class Athletics {
    static final CountDownLatch START_GUN = new CountDownLatch(1);
    static final LocalDateTime DATE_TIME = LocalDateTime.now();
    static volatile boolean over = false;
    static long startTime;
    static final int PICTURE_TIME = 20;
    static final int PICTURE_TIME2 = 30;

    public static void main(String[] args) throws InterruptedException {
        int num = 8;
        CountDownLatch latch = new CountDownLatch(num);
        List athletes = initAthletes(num, latch);
        athletes.stream().forEach(athlete -> athlete.start());
        System.out.println("裁判等待选手就位");
        Computer computer = new Computer(athletes);
        computer.start();
        latch.await();
        System.out.println(DATE_TIME + "时裁判开枪");
        startTime = Instant.now().toEpochMilli();
        START_GUN.countDown();
        computer.join();
        computer.showPhotos();
    }

    private static List initAthletes(int num, CountDownLatch latch) {
        return IntStream.range(0, num).mapToObj(i -> new Athlete(String.valueOf((char) ('A' + i)), latch)).collect(Collectors.toList());
    }

    static class Computer extends Thread {
        List> pictures = new ArrayList<>();

        static class Picture {
            final List pictureItems;
            final long timestamp;

            public Picture(List items) {
                this.pictureItems = Collections.unmodifiableList(items);
                ;
                this.timestamp = Instant.now().toEpochMilli();
            }

            public void show() {
                pictureItems.stream().forEach(item -> System.out.println(item));
            }

            @Override
            public String toString() {
                return "照片拍摄于" + LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneId.systemDefault()) +
                    ":" + pictureItems +
                    '}';
            }
        }

        final List athletes;

        public Computer(List athletes) {
            this.athletes = Collections.unmodifiableList(athletes);
        }

        public List compute() {
            return athletes.stream().map(new Function() {
                @Override
                public Athlete apply(Athlete athlete) {
                    try {
                        //拍照,返回运动员的成绩快照
                        return (Athlete) athlete.clone();
                    } catch (CloneNotSupportedException e) {
                        e.printStackTrace();
                    }
                    throw new RuntimeException("计算机故障");
                }
            }).sorted(Comparator.reverseOrder()).collect(Collectors.toList());
        }

        @Override
        public void run() {
            try {
                System.out.println("电脑已启动");
                START_GUN.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("\n电脑开始工作");
            sleepThenTakeFirstPhoto();
            while (!over && !isInterrupted()) {
                System.out.println();
                long currentSecond = (Instant.now().toEpochMilli() - startTime) / 1000 + 1;
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                List sortedAthletes = compute();
                System.out.print(currentSecond + "秒: ");
                sortedAthletes.stream().forEach(athlete -> System.out.print(athlete.getName() + " " + athlete.curLength + " "));
                if (currentSecond >= PICTURE_TIME2) {
                    //第二次拍照
                    takePhoto(sortedAthletes);
                    over = true;
                    break;
                }
            }
        }

        private void sleepThenTakeFirstPhoto() {
            while (true) {
                long currentSecond = (Instant.now().toEpochMilli() - startTime) / 1000 + 1;
                try {
                    TimeUnit.SECONDS.sleep(1);
                    System.out.print(currentSecond + "秒  ");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (PICTURE_TIME <= currentSecond) {
                    System.out.println(currentSecond + "秒");
                    //第一次拍照
                    List sortedAthletes = compute();
                    System.out.print(currentSecond + "秒: ");
                    sortedAthletes.stream().forEach(athlete -> System.out.print(athlete.getName() + " " + athlete.curLength + " "));
                    takePhoto(sortedAthletes);
                    break;
                }
            }
        }

        private  void takePhoto(List datas) {
            System.out.print("\ttakePhoto");
            pictures.add(new Picture(datas));
        }

        public void showPhotos() {
            System.out.println("\n打印照片");
            pictures.stream().forEach(e -> System.out.println(e));
        }

    }

    static class Athlete extends Thread implements Comparable, Cloneable {
        final CountDownLatch latch;
        final String name;
        private volatile int curLength = 0;

        public Athlete(String name, CountDownLatch latch) {
            super(name);
            this.name = name;
            this.latch = latch;
        }

        public void ready() {
            System.out.println(this.name + " 进场");
            try {
                TimeUnit.MILLISECONDS.sleep(ThreadLocalRandom.current().nextInt(100));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("选手" + this.name + " 准备好了,等待发令枪");
            latch.countDown();
        }

        @Override
        public void run() {
            ready();
            try {
                START_GUN.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.print("选手" + this.name + " 起跑\t");
            doRun();
        }

        private void doRun() {
            while (!over && !isInterrupted()) {
                curLength += ThreadLocalRandom.current().nextInt(8)+1;
                //模拟秒速
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        @Override
        public int compareTo(Athlete o) {
            return Integer.compare(this.curLength, o.curLength);
        }

        @Override
        protected Object clone() throws CloneNotSupportedException {
            Athlete athlete = new Athlete(this.name, null);
            athlete.curLength = this.curLength;
            return athlete;
        }

        @Override
        public String toString() {
            return "Athlete{" +
                "name='" + name + '\'' +
                ", curLength=" + curLength +
                '}';
        }
    }
}

你可能感兴趣的:(Java)