题目:一个文件中有10000个数,用Java实现一个多线程程序将这个10000个数输出到5个不用文件中(不要求输出到每个文件中的数量相同)。要求启动10个线程,两两一组,分为5组……

这篇文章使用的思想来源于:“随缘剑客”的一篇文章
题目:
一个文件中有10000个数,用Java实现一个多线程程序将这个10000个数输出到5个不用文件中(不要求输出到每个文件中的数量相同)。要求启动10个线程,两两一组,分为5组。每组两个线程分别将文件中的奇数和偶数输出到该组对应的一个文件中,需要偶数线程每打印10个偶数以后,就将奇数线程打印10个奇数,如此交替进行。同时需要记录输出进度,每完成1000个数就在控制台中打印当前完成数量,并在所有线程结束后,在控制台打印”Done”.
思想大纲:
首先创建存储10000个数的文本文件,把10000个数字取出来放在数组中,然后分为5个文件,每个文件里面放置2000个数字,一个文件下面设置两个线程,一个用于输出偶数,一个用于输出奇数,两个线程中的参数是同一个MyRunnable类,MyRunnable类中的count等于全部线程放入数字的总数目,虽然只有两个线程是同一个MyRunnable,但是count是静态的,无论新建多少个对象,都只有一个count,里面的数值可以改变,但是不能新建count,里面还有一个变量是lock,这个的目的是保证只能有一个线程进行count++以及输出相关文字的,其他的线程只能等待,当进行操作之后,其他的线程再进来也不会在输出相关文字了,里面还有两个参数是EVEN和ODD,这个的目的就是代表属于的是偶数还是奇数,毕竟有两个线程,通过对type的操控,刚开始让type是EVEN,后来放入十个偶数之后把type取反,然后这个时候就可以放入奇数了,然后放入十个奇数之后在把type取反,然后就可以在放入偶数了,循环罔替,PrintWriter writer是让我往哪个文件里面放数字的,int[] records是存有那两千个数的数组,evenPoint和oddPoint分别是偶数点和奇数点的标记,当往文件里面输入偶数或者奇数的时候,无论是不是成功,都需要+1,原因就是让下一次找偶数或者奇数更方便,当成功把偶数或者奇数放置在文件中的时候才进行i++,这样可以保证放置的偶数或者奇数一定是10个,每放置一次数,count就+1,当放置的数目是1000的整数倍,就输出1次,如果输出的是10000,再多输出一个Done!,如果奇数或者偶数输出完了,但是里面没发现奇数或者偶数了,那就退出for循环,即使没有输入10个也是如此,如果全部的数字都输入完了,代表的标志就是偶数或者奇数的数目都达到了2000,然后循环先把之前的等待的线程放了,然后返回false,这个时候while就结束了,标志一个文件里面放置2000个数已经完成了,五次循环之后,五个文件里面都放置了2000个数字;不过需要注意的有三个地方,分别是PrintWriter不能多次利用,每利用一次就需要重新定义一个,不然会出错误,还有一个就是EVEN和ODD只能是0和-1,不然~没用,如果你使用别的方法也可以最后一个就是一定要flush(),并且要及时flush()
代码如下:

public class Test {
    public static void main(String[] args) {
        PrintWriter printWriter = null;
        PrintWriter writer = null;
        BufferedReader bufferedReader = null;
        try {
            printWriter = new PrintWriter("input.txt");
            Random random = new Random();
            for (int i = 0; i < 10000; i++) {
                int nextInt = random.nextInt(1000);
                printWriter.print(nextInt + " ");
            }
            printWriter.flush();
            bufferedReader = new BufferedReader(new FileReader("input.txt"));
            String s = null;
            StringBuilder str = new StringBuilder();
            while ((s = bufferedReader.readLine()) != null) {
                str.append(s);
            }
            String[] split = str.toString().split(" ");
            int m = 0;
            for (int i = 0; i < 5; i++) {
                int[] records = new int[2000];
                for (int j = 0; j < 2000; j++) {
                    records[j] = Integer.parseInt(split[m]);
                    m++;
                }
                writer = new PrintWriter("output" + i + ".txt");
                MyRunnable myRunnable = new MyRunnable(records, writer);

                new Thread(myRunnable).start();
                new Thread(myRunnable).start();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (printWriter != null) {
                printWriter.close();
            }
            if (writer != null) {
                printWriter.close();
            }
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

class MyRunnable implements Runnable {
    private static int count = 0;
    private static final Object lock = new Object();
    private static final int EVEN = 0;
    private static final int ODD = -1;

    private int type;
    private PrintWriter writer;
    private int[] records;
    private int evenPoint = 0;
    private int oddPoint = 0;

    public MyRunnable(int[] records, PrintWriter writer) {
        this.records = records;
        this.writer = writer;
        this.type = EVEN;
    }

    @Override
    public void run() {
        while (print()) ;
    }

    private synchronized boolean print() {
        for (int i = 0; i < 10; ) {
            if (evenPoint >= records.length && oddPoint >= records.length) {
                notifyAll();
                return false;
            }
            if ((evenPoint >= records.length && type == EVEN) || (oddPoint >= records.length && type == ODD)) {
                break;
            }
            if (type == EVEN) {
                if (records[evenPoint] % 2 == 0) {
                    i++;
                    writer.print(records[evenPoint] + " ");
                    writer.flush();
                    synchronized (lock) {
                        count++;
                        if (count % 1000 == 0) {
                            System.out.println("已经打印了" + count+"个");
                            if (count == 10000) {
                                System.out.println("Done!");
                            }
                        }
                    }
                }
                evenPoint++;
            } else {
                if (records[oddPoint] % 2 == 1) {
                    i++;
                    writer.print(records[oddPoint] + " ");
                    writer.flush();
                    synchronized (lock) {
                        count++;
                        if (count % 1000 == 0) {
                            System.out.println("已经打印了" + count+"个");
                            if (count == 10000) {
                                System.out.println("Done!");
                            }
                        }
                    }
                }
                oddPoint++;
            }
        }
        type = ~type;
        notifyAll();
        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return true;
    }
}

结果:

已经打印了1000个
已经打印了2000个
已经打印了3000个
已经打印了4000个
已经打印了5000个
已经打印了6000个
已经打印了7000个
已经打印了8000个
已经打印了9000个
已经打印了10000个
Done!
可以使用 Java多线程技术来实现这个需求,具体实现流程如下: 1. 定义一个 Order 类,包含订单的详细信息,如订单 ID、订单更新时间等属性。 2. 定义一个 OrderFetcher 类,用于获取单个订单的详细信息,通过调用 /api/order/{id} 接口实现。 3. 定义一个 OrderRefreshTask 类,继承自 Java 的 TimerTask 类,用于刷新订单信息。在 run 方法,遍历订单列表,分别创建 OrderFetcher 对象,获取订单的详细信息,并更新订单的最后更新时间。 4. 定义一个 OrderManager 类,用于管理订单信息。在该类,定义一个 List<Order> 类型的成员变量,用于保存订单列表。在构造函数,初始化订单列表,并启动 OrderRefreshTask 定时任务。 5. 在页面上添加一个"刷新"按钮,点击该按钮时,调用 OrderManager 类的 refresh 方法,重新获取订单信息,并按订单最后更新时间倒序排列。 示例代码如下: ```java import java.util.*; import java.util.concurrent.*; public class Order { private int id; private Date updateTime; public Order(int id, Date updateTime) { this.id = id; this.updateTime = updateTime; } public int getId() { return id; } public Date getUpdateTime() { return updateTime; } public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; } } class OrderFetcher { public Order fetchOrder(int id) { // 调用 /api/order/{id} 接口获取订单信息 // 返回 Order 对象 return null; } } class OrderRefreshTask extends TimerTask { private List<Order> orders; public OrderRefreshTask(List<Order> orders) { this.orders = orders; } @Override public void run() { // 遍历订单列表,分别获取订单信息,并更新订单的最后更新时间 for (Order order : orders) { OrderFetcher fetcher = new OrderFetcher(); Order newOrder = fetcher.fetchOrder(order.getId()); newOrder.setUpdateTime(new Date()); order.setUpdateTime(newOrder.getUpdateTime()); } } } class OrderManager { private List<Order> orders; private Timer timer; public OrderManager() { // 初始化订单列表 orders = new ArrayList<>(); for (int i = 1; i <= 10; i++) { Order order = new Order(i, new Date()); orders.add(order); } // 启动定时任务,每隔 10 秒钟刷新一次订单信息 timer = new Timer(); timer.schedule(new OrderRefreshTask(orders), 0, 10000); } public List<Order> getOrders() { return orders; } public void refresh() { // 重新获取订单信息,并按订单最后更新时间倒序排列 Collections.sort(orders, new Comparator<Order>() { @Override public int compare(Order o1, Order o2) { return o2.getUpdateTime().compareTo(o1.getUpdateTime()); } }); } } class Main { public static void main(String[] args) { // 创建订单管理器 OrderManager manager = new OrderManager(); // 页面上添加一个"刷新"按钮,点击该按钮时,调用 OrderManager 类的 refresh 方法 manager.refresh(); } } ``` 注意,以上示例代码的 OrderFetcher 类和 /api/order/{id} 接口实现没有实际意义,需要根据实际情况进行修改。同时,定时任务的时间间隔也需要根据实际情况进行调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值