JAVA多线程笔试题-多个线程向多个文件写入内容

四个线程t1,t2,t3,t4,向4个文件中写入数据,t1只能写入1,t2只能写入2,t3只能写入3,t4只能写入4 

对4个文件A,B,C,D写入如下内容:
A:123412341234.....
B:234123412341....
C:341234123412....
D:412341234123....
怎么实现同步可以让线程并行工作?

从网络上看到有些人贴出的代码的答案,用一个锁来将4个文件全部锁了,然后让一个线程拥有锁,这个线程写了之后去唤醒下一个线程继续写,也就是说,这4个文件,同时只能有一个线程在写,这样跟单线程的有什么区别,这就是为了多线程而多线程。

我就尝试着来实现了一下。

感觉这个问题非常的有意思,每个线程只能写入特定的数字,这个有点麻烦,不过好歹是写出来了

如果有更好的实现方式,请大佬赐教

思路分析:

一个线程只能写一种字符,那么我们就让当前线程去遍历尝试每一个文件,判断当前文件的状态是不是能够由当前线程来进行写操作(用多个变量来来保存多个文件的状态),不能写就换下一个文件。

其中需要注意的问题就在于,我们每个文件中写的字符数量应该是一样的,如果简单的实现上面的思想,而不进行控制的话,结果就可能会导致每个文件被写入的字符数量不一致。其原因就在于多个线程可能会在一个文件中不断的尝试,不断的去改变一个文件的状态,最终导致更多的字符写入了一个文件。而且写入的字符数量也不能很好的进行控制,

那么如何来进行控制呢?

下面的代码就进行了展示

1.第一版代码,刚开始看起来没什么问题,但是后来发现了一个致命的问题,在代码中进行了说明,在第二版进行了修正

public class T {
    public static void main(String[] args) throws IOException, InterruptedException {
        /**
         * 每一个变量控制当前文件应该写的字符是什么
         * 这里使用AtomicInteger并不是线程安全考虑,而是为了使用一个可变的Integer类
         * 当然也可以自己写一个,这里就图省事了
         */
        AtomicInteger count1 = new AtomicInteger(1);
        AtomicInteger count2 = new AtomicInteger(2);
        AtomicInteger count3 = new AtomicInteger(3);
        AtomicInteger count4 = new AtomicInteger(4);

        FileWriter file1 = new FileWriter(new File("C:\\Users\\12130\\Desktop\\新建文件夹\\1.txt"));
        FileWriter file2 = new FileWriter(new File("C:\\Users\\12130\\Desktop\\新建文件夹\\2.txt"));
        FileWriter file3 = new FileWriter(new File("C:\\Users\\12130\\Desktop\\新建文件夹\\3.txt"));
        FileWriter file4 = new FileWriter(new File("C:\\Users\\12130\\Desktop\\新建文件夹\\4.txt"));
        Handler handler1 = new Handler(
                file1, file2, file3, file4, count1, count2, count3, count4, 1000, 1);
        Thread t1 = new Thread(handler1);
        Handler handler2 = new Handler(
                file1, file2, file3, file4, count1, count2, count3, count4, 1000, 2);
        Thread t2 = new Thread(handler2);
        Handler handler3 = new Handler(
                file1, file2, file3, file4, count1, count2, count3, count4, 1000, 3);
        Thread t3 = new Thread(handler3);
        Handler handler4 = new Handler(
                file1, file2, file3, file4, count1, count2, count3, count4, 1000, 4);
        Thread t4 = new Thread(handler4);
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t1.join();
        t2.join();
        t3.join();
        t4.join();
        file1.close();
        file2.close();
        file3.close();
        file4.close();
    }
}

class Handler implements Runnable {
    private final FileWriter file1;
    private final FileWriter file2;
    private final FileWriter file3;
    private final FileWriter file4;
    private AtomicInteger count1;
    private AtomicInteger count2;
    private AtomicInteger count3;
    private AtomicInteger count4;
    private int count;
    private int rtc;

    public Handler(FileWriter file1, FileWriter file2, FileWriter file3, FileWriter file4, AtomicInteger count1, AtomicInteger count2, AtomicInteger count3, AtomicInteger count4, int count, int rtc) throws IOException {
        this.file1 = file1;
        this.file2 = file2;
        this.file3 = file3;
        this.file4 = file4;
        this.count1 = count1;
        this.count2 = count2;
        this.count3 = count3;
        this.count4 = count4;
        this.count = count;
        this.rtc = rtc;
    }

    @Override
    public void run() {
        try {
            /**
             * 依次去尝试让每一个文件中写,如果当前文件的状态不能由当前文件来写
             * 那么当前线程将会阻塞,等到其他线程将当前文件的状态写成当前线程能写的状态
             * 当前线程就被唤醒,继续往下写。
             * 这样就是为了控制字符的写入,保证了每一次循环都会先每一个文件写一个字符
             * 最终每个文件的字符数量都是相同的,且写入的字符的数量也是受我们控制的。
             *
             * 存在的bug就是如果1文件当前最后一个字符写的是1,当前1线程来尝试写当前文件,1线程进入等待状态
             * 同时2文件当前最后一个字符是2,那么2线程来参数写,2线程也会进入等待状态
             * 3线程和4线程同理,最终导致每一个线程都处于了等待状态。
             */
            while (count > 0) {
                write(file1, count1, rtc);
                count--;
                write(file2, count2, rtc);
                count--;
                write(file3, count3, rtc);
                count--;
                write(file4, count4, rtc);
                count--;
            }
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void write(final FileWriter file, AtomicInteger count, int c) throws IOException, InterruptedException {
        synchronized (file) {
            if (count.get() != c) {
                /**
                 *
                 */
                file.wait();
            }
            file.write(c + "");
            int i = count.incrementAndGet();
            if (i == 5) {
                count.set(1);
            }
            file.notify();
        }
    }
}

2.第二版,应该没有bug了吧,且每个线程之间是并行的,感觉效率还不错

public class T {
    public static void main(String[] args) throws IOException, InterruptedException {
        /**
         * 每一个变量控制当前文件应该写的字符是什么
         */
        AtomicInteger count1 = new AtomicInteger(1);
        AtomicInteger count2 = new AtomicInteger(2);
        AtomicInteger count3 = new AtomicInteger(3);
        AtomicInteger count4 = new AtomicInteger(4);

        FileWriter file1 = new FileWriter(new File("C:\\Users\\12130\\Desktop\\新建文件夹\\1.txt"));
        FileWriter file2 = new FileWriter(new File("C:\\Users\\12130\\Desktop\\新建文件夹\\2.txt"));
        FileWriter file3 = new FileWriter(new File("C:\\Users\\12130\\Desktop\\新建文件夹\\3.txt"));
        FileWriter file4 = new FileWriter(new File("C:\\Users\\12130\\Desktop\\新建文件夹\\4.txt"));
        Handler handler1 = new Handler(
                file1, file2, file3, file4, count1, count2, count3, count4, 1000000, 1);
        Thread t1 = new Thread(handler1);
        Handler handler2 = new Handler(
                file1, file2, file3, file4, count1, count2, count3, count4, 1000000, 2);
        Thread t2 = new Thread(handler2);
        Handler handler3 = new Handler(
                file1, file2, file3, file4, count1, count2, count3, count4, 1000000, 3);
        Thread t3 = new Thread(handler3);
        Handler handler4 = new Handler(
                file1, file2, file3, file4, count1, count2, count3, count4, 1000000, 4);
        Thread t4 = new Thread(handler4);
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t1.join();
        t2.join();
        t3.join();
        t4.join();
        file1.close();
        file2.close();
        file3.close();
        file4.close();
    }
}

class Handler implements Runnable {
    private final FileWriter file1;
    private final FileWriter file2;
    private final FileWriter file3;
    private final FileWriter file4;
    /**
     * 指示某一个文件当前应该写入的字符
     */
    private AtomicInteger count1;
    private AtomicInteger count2;
    private AtomicInteger count3;
    private AtomicInteger count4;
    /**
     * count表示当前线程需要给每个文件写多少个rtc
     */
    private int count;
    /**
     * 当前线程应该写入的字符
     */
    private int rtc;

    public Handler(FileWriter file1, FileWriter file2, FileWriter file3, FileWriter file4, AtomicInteger count1, AtomicInteger count2, AtomicInteger count3, AtomicInteger count4, int count, int rtc) throws IOException {
        this.file1 = file1;
        this.file2 = file2;
        this.file3 = file3;
        this.file4 = file4;
        this.count1 = count1;
        this.count2 = count2;
        this.count3 = count3;
        this.count4 = count4;
        this.count = count;
        this.rtc = rtc;
    }

    @Override
    public void run() {
        try {
            /**
             * 每一次循环都尝试向每一个文件中写入一次当前线程的rtc
             */
            while (count > 0) {
                int i = 0;
                /**
                 * 必须要保证每一个文件在当前都写入了1。
                 * 不会进行阻塞,一直循环判断哪个文件当前线程能写
                 */
                while (i != 15) {
                    if ((i | 14) != 15 && write(file1, count1)) {
                        i |= 1;
                    }
                    if ((i | 13) != 15 && write(file2, count2)) {
                        i |= 2;
                    }
                    if ((i | 11) != 15 && write(file3, count3)) {
                        i |= 4;
                    }
                    if ((i | 7) != 15 && write(file4, count4)) {
                        i |= 8;
                    }
                }
                count--;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 尝试向文件中写入字符
     *
     * @param file  文件
     * @param count 当前文件当前状态应该写入的字符
     * @return 写入是否成功
     * @throws IOException
     */
    private boolean write(final FileWriter file, AtomicInteger count) throws IOException {
        if (count.get() != rtc) {
            /**
             * 如果当前文件不能写当前字符,直接退出,而不是阻塞在这个。
             * 前文件不能写入当前rtc,不代表其他文件不能写入
             * 不能阻塞在这里,否则可能会导致每一个线程都处于等待状态
             */
            return false;
        }
        file.write(rtc + "");
        int i = count.incrementAndGet();
        if (i == 5) {
            count.set(1);
        }
        return true;
    }
}

 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值