Java代码编程实现模拟机器人对话

简介: 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 的目的。

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

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


二、创建线程并运行

接下来,我们使用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;
    }
}

4.创建ThreadTest对象的main函数,启动2个线程,观察运行结果(每次结果可能都不一样):

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函数结束了。");
    }
}

5.运行ThreadTest.java,观察结果,体会多线程的工作原理。


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

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

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

相关文章
|
7天前
|
JavaScript NoSQL Java
接替此文【下篇-服务端+后台管理】优雅草蜻蜓z系统JAVA版暗影版为例-【蜻蜓z系列通用】-2025年全新项目整合搭建方式-这是独立吃透代码以后首次改变-独立PC版本vue版搭建教程-优雅草卓伊凡
接替此文【下篇-服务端+后台管理】优雅草蜻蜓z系统JAVA版暗影版为例-【蜻蜓z系列通用】-2025年全新项目整合搭建方式-这是独立吃透代码以后首次改变-独立PC版本vue版搭建教程-优雅草卓伊凡
152 96
接替此文【下篇-服务端+后台管理】优雅草蜻蜓z系统JAVA版暗影版为例-【蜻蜓z系列通用】-2025年全新项目整合搭建方式-这是独立吃透代码以后首次改变-独立PC版本vue版搭建教程-优雅草卓伊凡
|
1月前
|
SQL Java 数据库连接
如何在 Java 代码中使用 JSqlParser 解析复杂的 SQL 语句?
大家好,我是 V 哥。JSqlParser 是一个用于解析 SQL 语句的 Java 库,可将 SQL 解析为 Java 对象树,支持多种 SQL 类型(如 `SELECT`、`INSERT` 等)。它适用于 SQL 分析、修改、生成和验证等场景。通过 Maven 或 Gradle 安装后,可以方便地在 Java 代码中使用。
271 11
|
1月前
|
JSON Java 数据挖掘
利用 Java 代码获取淘宝关键字 API 接口
在数字化商业时代,精准把握市场动态与消费者需求是企业成功的关键。淘宝作为中国最大的电商平台之一,其海量数据中蕴含丰富的商业洞察。本文介绍如何通过Java代码高效、合规地获取淘宝关键字API接口数据,帮助商家优化产品布局、制定营销策略。主要内容包括: 1. **淘宝关键字API的价值**:洞察用户需求、优化产品标题与详情、制定营销策略。 2. **获取API接口的步骤**:注册账号、申请权限、搭建Java开发环境、编写调用代码、解析响应数据。 3. **注意事项**:遵守法律法规与平台规则,处理API调用限制。 通过这些步骤,商家可以在激烈的市场竞争中脱颖而出。
|
2月前
|
存储 缓存 Java
Java 并发编程——volatile 关键字解析
本文介绍了Java线程中的`volatile`关键字及其与`synchronized`锁的区别。`volatile`保证了变量的可见性和一定的有序性,但不能保证原子性。它通过内存屏障实现,避免指令重排序,确保线程间数据一致。相比`synchronized`,`volatile`性能更优,适用于简单状态标记和某些特定场景,如单例模式中的双重检查锁定。文中还解释了Java内存模型的基本概念,包括主内存、工作内存及并发编程中的原子性、可见性和有序性。
Java 并发编程——volatile 关键字解析
|
2月前
|
安全 Java 编译器
深入理解Java中synchronized三种使用方式:助您写出线程安全的代码
`synchronized` 是 Java 中的关键字,用于实现线程同步,确保多个线程互斥访问共享资源。它通过内置的监视器锁机制,防止多个线程同时执行被 `synchronized` 修饰的方法或代码块。`synchronized` 可以修饰非静态方法、静态方法和代码块,分别锁定实例对象、类对象或指定的对象。其底层原理基于 JVM 的指令和对象的监视器,JDK 1.6 后引入了偏向锁、轻量级锁等优化措施,提高了性能。
77 3
|
2月前
|
存储 安全 Java
Java多线程编程秘籍:各种方案一网打尽,不要错过!
Java 中实现多线程的方式主要有四种:继承 Thread 类、实现 Runnable 接口、实现 Callable 接口和使用线程池。每种方式各有优缺点,适用于不同的场景。继承 Thread 类最简单,实现 Runnable 接口更灵活,Callable 接口支持返回结果,线程池则便于管理和复用线程。实际应用中可根据需求选择合适的方式。此外,还介绍了多线程相关的常见面试问题及答案,涵盖线程概念、线程安全、线程池等知识点。
232 2
|
2月前
|
算法 Java 调度
java并发编程中Monitor里的waitSet和EntryList都是做什么的
在Java并发编程中,Monitor内部包含两个重要队列:等待集(Wait Set)和入口列表(Entry List)。Wait Set用于线程的条件等待和协作,线程调用`wait()`后进入此集合,通过`notify()`或`notifyAll()`唤醒。Entry List则管理锁的竞争,未能获取锁的线程在此排队,等待锁释放后重新竞争。理解两者区别有助于设计高效的多线程程序。 - **Wait Set**:线程调用`wait()`后进入,等待条件满足被唤醒,需重新竞争锁。 - **Entry List**:多个线程竞争锁时,未获锁的线程在此排队,等待锁释放后获取锁继续执行。
87 12
|
2月前
|
传感器 人工智能 自然语言处理
RDT:清华开源全球最大的双臂机器人操作任务扩散基础模型、代码与训练集,基于模仿能力机器人能够自主完成复杂任务
RDT(Robotics Diffusion Transformer)是由清华大学AI研究院TSAIL团队推出的全球最大的双臂机器人操作任务扩散基础模型。RDT具备十亿参数量,能够在无需人类操控的情况下自主完成复杂任务,如调酒和遛狗。
175 22
RDT:清华开源全球最大的双臂机器人操作任务扩散基础模型、代码与训练集,基于模仿能力机器人能够自主完成复杂任务
|
2月前
|
前端开发 Java 测试技术
java日常开发中如何写出优雅的好维护的代码
代码可读性太差,实际是给团队后续开发中埋坑,优化在平时,没有那个团队会说我专门给你一个月来优化之前的代码,所以在日常开发中就要多注意可读性问题,不要写出几天之后自己都看不懂的代码。
78 2
|
2月前
|
安全 算法 Java
Java多线程编程中的陷阱与最佳实践####
本文探讨了Java多线程编程中常见的陷阱,并介绍了如何通过最佳实践来避免这些问题。我们将从基础概念入手,逐步深入到具体的代码示例,帮助开发者更好地理解和应用多线程技术。无论是初学者还是有经验的开发者,都能从中获得有价值的见解和建议。 ####

热门文章

最新文章