Java多线程实现同步——wait()和notify()实现

Wesley13
• 阅读 616

要求:子线程循环5次,接着主线程循环10次,接着又回到子线程。如此循环50次。

实现以上要求的时候,除了直白的面向过程的实现,可以考虑面向对象的写法。

根据高内聚的原装,将子线程和主线程的操作都封装一起。

通过wait()和notify()进行同步。

class Business {
    private boolean shouldSub = true;
    public synchronized void sub(int k) {
        if (shouldSub) {
            for (int i=0 ; i<5 ; i++) {
                System.out.println("sub thread inner of " + i + " ,outer " + k);
            }
            shouldSub = false;
            this.notifyAll();
        } else {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    public synchronized void main(int k) {
        if (!shouldSub) {
            for (int i=0 ; i<10 ; i++) {
                System.out.println("main thread inner of " + i + " ,outer " + k);
            }
            shouldSub = true;
            this.notifyAll();
        } else {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class TraditionalThreadCommucation {

    public static void main(String[] args) {
        
        final Business business = new Business();
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int k=0; k<50 ;k++){
                    business.sub(k);
                }
            }
        }).start();
        
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int k=0; k<50 ;k++){
                    business.main(k);
                }
            }
        }).start();
    }
}

根据以上的设计思路,我们来解另一道题:

一个文件中有10000个数,用Java实现一个多线程程序将这个10000个数输出到5个不用文件中(不要求输出到每个文件中的数量相同)。要求启动10个线程,两两一组,分为5组。每组两个线程分别将文件中的奇数和偶数输出到该组对应的一个文件中,需要偶数线程每打印10个偶数以后,就将奇数线程打印10个奇数,如此交替进行。同时需要记录输出进度,每完成1000个数就在控制台中打印当前完成数量,并在所有线程结束后,在控制台打印”Done”.

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.util.Random;

public class MyPrintByThread {

    public static void main(String[] args) {
        try {
            PrintWriter pw = new PrintWriter(new FileWriter(new File("input.txt")),true);
            Random random = new Random();
            for (int i=0 ; i<10000 ; i++) {
                pw.print(Math.abs(random.nextInt()%100) + " ");
            }
            pw.flush();
            pw.close();
            
            BufferedReader reader = new BufferedReader(new FileReader("input.txt"));
            String str = reader.readLine();
            reader.close();
            
            String[] strs = str.split(" ");
            int j=0;
            for (int i=0 ; i<5 ;i++) {
                int records[] = new int[2000];
                for (int k=0 ; k<2000 ; k++) {
                    records[k] = Integer.parseInt(strs[j]);
                    j++;
                }
                PrintWriter writer = new PrintWriter(new FileWriter(new File("output"+i+".txt")),true);
                final Business business = new Business(writer, records);
                
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        business.printEven();
                    }
                });
                
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        business.printOdd();
                    }
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class Business {
    
    private boolean shouldEven = true;
    private int[] subRecords;
    private PrintWriter pw;
    private int evenPointer = 0;
    private int oddPointer = 0;
    
    public Business(PrintWriter pw,int[] subRecords) {
        this.pw = pw;
        this.subRecords = subRecords;
    }
    
    public synchronized void printEven() {
        if (shouldEven) {
            if (evenPointer <= subRecords.length) {
                for (int i=0 ; i<10 ;) {
                    if (subRecords[evenPointer] % 2 == 0) {
                        pw.print(subRecords[evenPointer] + " ");
                        
                        if (evenPointer % 1000 == 0)
                            System.out.println("已经打印:" + evenPointer);
                        i++;
                    } 
                    evenPointer++;
                }
            }
            shouldEven = false;
            this.notify();
        } else {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    public synchronized void printOdd() {
        if (!shouldEven) {
            if (oddPointer <= subRecords.length) {
                for (int i=0 ; i<10 ;) {
                    if (subRecords[oddPointer] % 2 != 0) {
                        pw.print(subRecords[oddPointer] + " ");
                        
                        if (evenPointer % 1000 == 0)
                            System.out.println("已经打印:" + oddPointer);
                        i++;
                    } 
                    oddPointer++;
                }
            }
            shouldEven = true;
            this.notify();
        } else {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

代码未经过测试,热心的朋友可以给我留言,支出修改的地方。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
zdd小小菜鸟 zdd小小菜鸟
2年前
多线程面试
多线程篇1.为什么要使用线程池tex避免频繁地创建和销毁线程,达到线程对象的重用。另外,使用线程池还可以根据项目灵活地控制并发的数目。2.java中如何获取到线程dump文件tex死循环、死锁、阻
Wesley13 Wesley13
3年前
4、jstack查看线程栈信息
1、介绍利用jps、top、jstack命令找到进程中耗时最大的线程,以及线程状态等等,同时最后还可以显示出死锁的线程查找:FoundoneJavaleveldeadlock即可1、jps获得进程号!(https://oscimg.oschina.net/oscnet/da00a309fa6
Wesley13 Wesley13
3年前
探索JAVA并发
\sleep/wait/notify/notifyAll分别有什么作用?它们的区别是什么?wait时为什么要放在循环里而不能直接用if?简介首先对几个相关的方法做个简单解释,Object中有几个用于线程同步的方法:wait、notify、notifyAll。publicclassObject{public
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Wesley13 Wesley13
3年前
Java并发编程:多线程如何实现阻塞与唤醒
线程的阻塞和唤醒在多线程并发过程中是一个关键点,当线程数量达到很大的数量级时,并发可能带来很多隐蔽的问题。如何正确暂停一个线程,暂停后又如何在一个要求的时间点恢复,这些都需要仔细考虑的细节。Java为我们提供了多种API来对线程进行阻塞和唤醒操作,比如suspend与resume、sleep、wait与notify以及park与unpark等等。!(
Wesley13 Wesley13
3年前
Java并发
最简单的东西,往往包含了最复杂的实现,因为需要为上层的存在提供一个稳定的基础,Object作为java中所有对象的基类,其存在的价值不言而喻,其中wait和notify方法的实现多线程协作提供了保证。案例publicclassWaitTestDemo{publicstaticvoidmain(Strin
Wesley13 Wesley13
3年前
Java 并发编程:多线程如何实现阻塞与唤醒
线程的阻塞和唤醒在多线程并发过程中是一个关键点,当线程数量达到很大的数量级时,并发可能带来很多隐蔽的问题。如何正确暂停一个线程,暂停后又如何在一个要求的时间点恢复,这些都需要仔细考虑的细节。Java为我们提供了多种API来对线程进行阻塞和唤醒操作,比如suspend与resume、sleep、wait与notify以及park与unpark等等。!(
使用asyncio库和多线程实现高并发的异步IO操作的爬虫
摘要:本文介绍了如何使用Python的asyncio库和多线程实现高并发的异步IO操作,以提升爬虫的效率和性能。通过使用asyncio的协程和事件循环,结合多线程,我们可以同时处理多个IO任务,并实现对腾讯新闻网站的高并发访问。正文:在网络爬虫中,IO操作