如何用Java代码编程实现模拟机器人对话?

 前言

今天带大家来体验一下Java多线程,首先我们要明白什么是线程?什么是多线程?

进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程。比如在Windows系统中,一个运行的exe就是一个进程。

线程是指进程中的一个执行流程,一个进程可以运行多个线程。比如java.exe进程可以运行很多线程。线程总是输入某个进程,进程中的多个线程共享进程的内存。

多线程指的是这个程序(一个进程)运行时产生了不止一个线程。

目录

一、Java多线程的介绍

二、创建线程并运行

三、多线程间的交互

①实践模拟两个机器人对话


一、Java多线程的介绍

我们知道,Java编写程序都运行在在Java虚拟机JVM)中,在JVM的内部,程序的多任务是通过线程来实现的。每用java命令启动一个java应用程序,就会启动一个JVM进程。在同一个JVM进程中,有且只有一个进程,就是它自己。在这个JVM环境中,所有程序代码的运行都是以线程来运行。

一般常见的Java应用程序都是单线程的。比如,用java命令运行一个最简单的HelloWorld的Java应用程序时,就启动了一个JVM进 程,JVM找到程序程序的入口点main(),然后运行main()方法,这样就产生了一个线程,这个线程称之为主线程。当main方法结束后,主线程运行完成。JVM进程也随即退出 。

对于一个进程中的多个线程来说,多个线程共享进程的内存块,当有新的线程产生的时候,操作系统不分配新的内存,而是让新线程共享原有的进程块的内存。因此,线程间的通信很容易,速度也很快。不同的进程因为处于不同的内存块,因此进程之间的通信相对困难

多线程能满足程序员编写高效率的程序来达到充分利用 CPU 的目的。

线程是一个动态执行的过程,它也有一个从产生到死亡的过程。

下图显示了一个线程完整的生命周期:

42cf1dca1e424dfe8ba5a8644f3eb414.png


 二、创建线程并运行

接下来,我们使用Thread创建一个线程并运行:

1.打开Idea新建工程,再右击src新建包Thread,在包上点右键,创建一个PeopleA类,输入代码:

package Thread;

public class PeopleA extends Thread{
    @Override
    public void run() { //被调用start方法后,就会执行run方法里的代码
        System.out.println(this.getName() + " 线程开始执行了:");
        try {
            Thread.sleep(5000); //休眠5秒,模拟子线程需要5秒才能完成任务。
        } catch (InterruptedException e) {
        e.printStackTrace();//在命令行打印异常信息在程序中出错的位置及原因。
        }
        System.out.println(this.getName() + " 线程执行结束了:");
    }
}

2.再右击Thread包创建一个ThreadTest类,并输入代码:

package Thread;

public class ThreadTest {
    public static void main(String[] args) {
        //在mian 线程(主线程)中创建了一个子线程 peopleA
        PeopleA peopleA = new PeopleA();
        //给子线程取个名字:A线程
        peopleA.setName("A线程");
        //启动peopleA线程,启动后系统将增加一个线程去执行PeopleA中的run方法里的代码
        peopleA.start();
        //打印这句表示主线程启动子线程后,会继续执行后续代码,不会关心子线程什么时候执行
        System.out.println("main函数结束了。");
    }
}

3.运行,查看结果,体会多线程的执行:

主线程启动子线程后,会继续执行后续代码,不会关心子线程什么时候执行。
这里还需注意,主线程的代码执行完毕后,整个程序并没有立即结束运行,而是等待子线程运行完后再结束运行并回收资源。

三、多线程间的交互

①模拟两个机器人的对话

1.我们右击src,新建一个包com.my.thread,并右击创建名为Language的对象,用来存储问题和答案,用于2个机器人的交互。代码如下:

package com.my.thread;

import java.util.Random;

//预先设定好可能的对话内容
public class Language {
    //问题集合
    static final String[] questions = {
            "你叫什么名字?",
            "现在几点了?",
            "你早饭吃的什么?",
            "你中午吃的什么?",
            "你晚餐吃的什么?",
            "你的身高多少?",
            "你最喜欢的Csdn博主是谁?"
    };
    //随机数生成器
    static Random random = new Random();
    //当前问题
    static String question = null;
    //当前答案
    static String answer = null;

    /**随机获取一个问题*/
    public static String getARandomQuestion() {
        int index = random.nextInt(questions.length);
        return questions[index];
    }
    //设置当前答案
    public static void setAnswer(String answer) {
        Language.answer = answer;
    }
    //设置当前问题
    public static void setQuestion(String question) {
        Language.question = question;
    }
}

2. 在com.my.thread包上创建名为PeopleA的对象,用来模拟提问者。代码如下:

package com.my.thread;

public class PeopleA extends Thread{
    @Override
    public void run() { //被调用start方法后,就会执行run方法里的代码
        System.out.println(this.getName() + " 我要开始提问了。");

        //使用死循环写法,让线程PeopleA永远不会自动停止运行
        while(true){
            //没有人回答问题 并且没有人提问的时候,就提一个问题
            if(Language.question == null) {
                String q = Language.getARandomQuestion();//获取一个随机问题
                Language.setQuestion(q);//设置问题
                System.out.println(this.getName() + ":" + q);
                Language.setAnswer(null);//提出问题后,把答案设置为空
            }else{
                System.out.println("请回答我的问题...");
            }

            try {
                //随机休眠0-15秒,模拟用户A的思考时间
                Thread.sleep(1000 * Language.random.nextInt(15));

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

    }
}

3. 在com.my.thread包上创建名为PeopleB的对象,用来模拟回答者。代码如下:

package com.my.thread;

import java.text.SimpleDateFormat;
import java.util.Date;

public class PeopleB extends Thread{
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    @Override
    public void run() { //被调用start方法后,就会执行run方法里的代码
        System.out.println(this.getName() + " 我准备好回答了。");

        //使用死循环写法,让线程PeopleB永远不会自动停止运行
        while(true){
            //有人提问,且没有人回答的情况下,就回答问题
            if(Language.answer == null) {
                String an = answerQuestion(Language.question); //根据问题得到答案
                Language.setAnswer(an);//设置答案
                System.out.println(this.getName() + ":" + an);//打印答案
                Language.question = null;//回答完毕后,把问题设置为空。
            }else{
                System.out.println("请你继续提问...");
            }

            try {
                //随机休眠0-15秒,模拟用户B的思考时间
                Thread.sleep(1000 * Language.random.nextInt(15));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

    //根据问题得到答案
    private String answerQuestion(String question) {
        if(question == null){
            return "请开始提问...";
        }
        String an = "这个问题太难了,答不上来。";//默认回答语句
        if(question.equals("你叫什么名字?")){
            an = this.getName();
        }else if(question.equals("现在几点了?")){
            an = format.format(new Date());
        }else if(question.equals("你早饭吃的什么?")){
            an = "豆浆油条。";
        }else if(question.equals("你的身高多少?")){
            an = "身高1米85。";
        }else if(question.equals("你最喜欢的Csdn博主是谁?")){
            an = "青00(一起学Java)";
        }else{

        }
        return an;
    }
}
package com.my.thread;

public class ThreadTest {
    public static void main(String[] args) {
        //在mian 线程(主线程)中创建了2个子线程 peopleA,peopleB
        PeopleA peopleA = new PeopleA();
        PeopleB peopleB = new PeopleB();
        //给子线程取个名字
        peopleA.setName("提问者");
        peopleB.setName("回答者");
        //启动peopleA,peopleB线程,启动后系统将增加一个线程去执行run方法里的代码
        peopleA.start();
        peopleB.start();
        //打印这句表示主线程启动子线程后,会继续执行后续代码,不会关心子线程什么时候执行
        System.out.println("main函数结束了。");
    }
}

cac4672c74ee402592e7ce6cdf6aeb60.png


多线程的使用注意事项:有效利用多线程的关键是理解程序是并发执行而不是串行执行的。

例如:程序中有两个子系统需要并发执行,这时候就需要利用多线程编程。通过对多线程的使用,可以编写出非常高效的程序。

请注意,如果你创建太多的线程,程序执行的效率实际上是降低了,而不是提升了。请记住,上下文的切换开销也很重要,如果你创建了太多的线程,CPU 花费在上下文的切换的时间将多于执行程序的时间!


 🥰以上就是本篇博客的全部内容,如果对你有用麻烦关注点赞收藏三连走一波!
👋如有问题欢迎留言,如有错误烦请指正,期待你的评论!

#Java开发##Java工程师#
全部评论

相关推荐

2025-12-12 19:01
南京航空航天大学 C++
秋招没咋投,准备 wxg 转正之后摆烂了。结果不堪字节 HR 的骚扰还是面了一下字节。之前想去字节的时候怎么面都挂。现在想着随便面一下结果三面技术面都意外顺利还有加面。十月中旬字节发了意向,wxg 转正结果无响应。十月底字节拉了保温群,wxg 口头通过,系统显示考核中。十一月初和字节 ld 交流之后得知 base 居然能选海外,甚至能小 wlb 一下,wxg 无响应无人联系。十一月中旬把字节 base 转到了海外,wxg 流程灰了,一问超时忘处理了,过两天又变考核中了。十一月下旬字节换了海外 HR 对接,问了期望薪资,wxg 考核终于显示通过,无 HR 保温,无其他保温。十一月底给字节报了个天价,想吓吓他们,同时告诉微信字节要开了,微信无响应。同样十一月底字节 HR 告诉我确实给不到那么高,但是能拿期权补上,问能不能接受。微信无响应。同样十一月底字节 HR 告知了具体方案,符合预期。 微信无响应。十二月上旬催 wxg 不开我就盲拒了,wxg HR 火急火燎的打电话问情况,问期望。我给了一个不算夸张的总包数字,因为今年市场在涨,过了三天还不联系我,我再催,约时间下午打电话,非得在我给出的数字上压下去几万,微信又不差这点,为什么不能满足我,让我没有拒绝的理由呢?一番纠结抗争,求稳还是追求挑战,最终选择接受迎接新的挑战,因为堂吉诃德永远不会停下脚步!回想起来,在 wxg 谈薪的阶段,我认为并没有给予我一定的重视,即使 HR 表示我在实习期间的表现和之前的面评都很靠前。也没有感觉到想要争取我,虽然我表示拒了 offer 之后要给我加面委定 t6 再涨,但我三个月没面试让我面面委那就是白给,还是算了。有缘再见了我亲爱的 wxg,再见了曾经的梦中情厂,再见亲爱的 mt,再见亲爱的朋友们。也再见,北京的一切。我想润了。秋招结束,卸载牛客,下一个三年,下一个五年,下一个十年后再来看看。
面试中的大熊猫爱吃薯...:我嫉妒得狗眼通红
点赞 评论 收藏
分享
当年还在美团那个倒霉的 Peppr 团队工作时,我一直有个疑问:这群人每天到底在自嗨什么。每次开会一堆人围着一堆“看起来很高级”的文档转,模板统一、名词复杂、页数感人,每一页都在暗示一件事:“你不懂,是因为你不专业。”但现实是——代码照样写在 💩 山上,该出问题还是会出问题,这真的很逗,系统一出问题,文档的唯一作用就是证明:“我们当初确实认真写过文档。”所以本质区别到底是什么?是代码质量提升了,还是大家在精神层面完成了一次“工程师 cosplay”?有句话说得好潮水退去才知道谁在裸泳。还记得当时的马哥、明哥(图 1 左)最爱反复强调一句话:“所有场景一定要想到。”、“这个场景为什么没考虑到?”不过他们这些话我是真的听进去了。不然我也不会在一年多前就说:这个项目活不过两年。顺带一提,那段时间还有个固定节目。每次下楼,总能听见我明哥在吐槽不同的人。我从他身后绕过去,经常能听到他一边抽烟一边说:“xx 这小子太坑了,回头我一定要跟马哥说说。”于是深谙人情世故但真不会抽烟的我也会从口袋掏出一支低尼古丁含量的烟给自己点上,假意自己什么都没听到什么都不知道,只是来抽烟的。后来我才明白,这可能也是团队文化的一部分:问题永远在别人身上,而我们,永远在复盘里😂。
秋招白月光
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务