Java實現(xiàn)模擬機器人對話的示例代碼
前言
今天帶大家來體驗一下Java多線程,首先我們要明白什么是線程?什么是多線程?
進程是指一個內(nèi)存中運行的應(yīng)用程序,每個進程都有自己獨立的一塊內(nèi)存空間,一個進程中可以啟動多個線程。比如在Windows系統(tǒng)中,一個運行的exe就是一個進程。
線程是指進程中的一個執(zhí)行流程,一個進程可以運行多個線程。比如java.exe進程可以運行很多線程。線程總是輸入某個進程,進程中的多個線程共享進程的內(nèi)存。
多線程指的是這個程序(一個進程)運行時產(chǎn)生了不止一個線程。
一、Java多線程的介紹
我們知道,Java編寫程序都運行在在Java虛擬機(JVM)中,在JVM的內(nèi)部,程序的多任務(wù)是通過線程來實現(xiàn)的。每用java命令啟動一個java應(yīng)用程序,就會啟動一個JVM進程。在同一個JVM進程中,有且只有一個進程,就是它自己。在這個JVM環(huán)境中,所有程序代碼的運行都是以線程來運行。
一般常見的Java應(yīng)用程序都是單線程的。比如,用java命令運行一個最簡單的HelloWorld的Java應(yīng)用程序時,就啟動了一個JVM進 程,JVM找到程序程序的入口點main(),然后運行main()方法,這樣就產(chǎn)生了一個線程,這個線程稱之為主線程。當(dāng)main方法結(jié)束后,主線程運行完成。JVM進程也隨即退出 。
對于一個進程中的多個線程來說,多個線程共享進程的內(nèi)存塊,當(dāng)有新的線程產(chǎn)生的時候,操作系統(tǒng)不分配新的內(nèi)存,而是讓新線程共享原有的進程塊的內(nèi)存。因此,線程間的通信很容易,速度也很快。不同的進程因為處于不同的內(nèi)存塊,因此進程之間的通信相對困難。
多線程能滿足程序員編寫高效率的程序來達到充分利用 CPU 的目的。
線程是一個動態(tài)執(zhí)行的過程,它也有一個從產(chǎn)生到死亡的過程。
下圖顯示了一個線程完整的生命周期:

二、創(chuàng)建線程并運行
接下來,我們使用Thread創(chuàng)建一個線程并運行:
1.打開Idea新建工程,再右擊src新建包Thread,在包上點右鍵,創(chuàng)建一個PeopleA類,輸入代碼:
package Thread;
public class PeopleA extends Thread{
@Override
public void run() { //被調(diào)用start方法后,就會執(zhí)行run方法里的代碼
System.out.println(this.getName() + " 線程開始執(zhí)行了:");
try {
Thread.sleep(5000); //休眠5秒,模擬子線程需要5秒才能完成任務(wù)。
} catch (InterruptedException e) {
e.printStackTrace();//在命令行打印異常信息在程序中出錯的位置及原因。
}
System.out.println(this.getName() + " 線程執(zhí)行結(jié)束了:");
}
}2.再右擊Thread包創(chuàng)建一個ThreadTest類,并輸入代碼:
package Thread;
public class ThreadTest {
public static void main(String[] args) {
//在mian 線程(主線程)中創(chuàng)建了一個子線程 peopleA
PeopleA peopleA = new PeopleA();
//給子線程取個名字:A線程
peopleA.setName("A線程");
//啟動peopleA線程,啟動后系統(tǒng)將增加一個線程去執(zhí)行PeopleA中的run方法里的代碼
peopleA.start();
//打印這句表示主線程啟動子線程后,會繼續(xù)執(zhí)行后續(xù)代碼,不會關(guān)心子線程什么時候執(zhí)行
System.out.println("main函數(shù)結(jié)束了。");
}
}3.運行,查看結(jié)果,體會多線程的執(zhí)行:
主線程啟動子線程后,會繼續(xù)執(zhí)行后續(xù)代碼,不會關(guān)心子線程什么時候執(zhí)行。
這里還需注意,主線程的代碼執(zhí)行完畢后,整個程序并沒有立即結(jié)束運行,而是等待子線程運行完后再結(jié)束運行并回收資源。
三、多線程間的交互
①模擬兩個機器人的對話
1.我們右擊src,新建一個包com.my.thread,并右擊創(chuàng)建名為Language的對象,用來存儲問題和答案,用于2個機器人的交互。代碼如下:
package com.my.thread;
import java.util.Random;
//預(yù)先設(shè)定好可能的對話內(nèi)容
public class Language {
//問題集合
static final String[] questions = {
"你叫什么名字?",
"現(xiàn)在幾點了?",
"你早飯吃的什么?",
"你中午吃的什么?",
"你晚餐吃的什么?",
"你的身高多少?",
"你最喜歡的Csdn博主是誰?"
};
//隨機數(shù)生成器
static Random random = new Random();
//當(dāng)前問題
static String question = null;
//當(dāng)前答案
static String answer = null;
/**隨機獲取一個問題*/
public static String getARandomQuestion() {
int index = random.nextInt(questions.length);
return questions[index];
}
//設(shè)置當(dāng)前答案
public static void setAnswer(String answer) {
Language.answer = answer;
}
//設(shè)置當(dāng)前問題
public static void setQuestion(String question) {
Language.question = question;
}
}2. 在com.my.thread包上創(chuàng)建名為PeopleA的對象,用來模擬提問者。代碼如下:
package com.my.thread;
public class PeopleA extends Thread{
@Override
public void run() { //被調(diào)用start方法后,就會執(zhí)行run方法里的代碼
System.out.println(this.getName() + " 我要開始提問了。");
//使用死循環(huán)寫法,讓線程PeopleA永遠不會自動停止運行
while(true){
//沒有人回答問題 并且沒有人提問的時候,就提一個問題
if(Language.question == null) {
String q = Language.getARandomQuestion();//獲取一個隨機問題
Language.setQuestion(q);//設(shè)置問題
System.out.println(this.getName() + ":" + q);
Language.setAnswer(null);//提出問題后,把答案設(shè)置為空
}else{
System.out.println("請回答我的問題...");
}
try {
//隨機休眠0-15秒,模擬用戶A的思考時間
Thread.sleep(1000 * Language.random.nextInt(15));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}3. 在com.my.thread包上創(chuàng)建名為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() { //被調(diào)用start方法后,就會執(zhí)行run方法里的代碼
System.out.println(this.getName() + " 我準(zhǔn)備好回答了。");
//使用死循環(huán)寫法,讓線程PeopleB永遠不會自動停止運行
while(true){
//有人提問,且沒有人回答的情況下,就回答問題
if(Language.answer == null) {
String an = answerQuestion(Language.question); //根據(jù)問題得到答案
Language.setAnswer(an);//設(shè)置答案
System.out.println(this.getName() + ":" + an);//打印答案
Language.question = null;//回答完畢后,把問題設(shè)置為空。
}else{
System.out.println("請你繼續(xù)提問...");
}
try {
//隨機休眠0-15秒,模擬用戶B的思考時間
Thread.sleep(1000 * Language.random.nextInt(15));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//根據(jù)問題得到答案
private String answerQuestion(String question) {
if(question == null){
return "請開始提問...";
}
String an = "這個問題太難了,答不上來。";//默認(rèn)回答語句
if(question.equals("你叫什么名字?")){
an = this.getName();
}else if(question.equals("現(xiàn)在幾點了?")){
an = format.format(new Date());
}else if(question.equals("你早飯吃的什么?")){
an = "豆?jié){油條。";
}else if(question.equals("你的身高多少?")){
an = "身高1米85。";
}else if(question.equals("你最喜歡的Csdn博主是誰?")){
an = "青00(一起學(xué)Java)";
}else{
}
return an;
}
}4.創(chuàng)建ThreadTest對象的main函數(shù),啟動2個線程,觀察運行結(jié)果(每次結(jié)果可能都不一樣):
package com.my.thread;
public class ThreadTest {
public static void main(String[] args) {
//在mian 線程(主線程)中創(chuàng)建了2個子線程 peopleA,peopleB
PeopleA peopleA = new PeopleA();
PeopleB peopleB = new PeopleB();
//給子線程取個名字
peopleA.setName("提問者");
peopleB.setName("回答者");
//啟動peopleA,peopleB線程,啟動后系統(tǒng)將增加一個線程去執(zhí)行run方法里的代碼
peopleA.start();
peopleB.start();
//打印這句表示主線程啟動子線程后,會繼續(xù)執(zhí)行后續(xù)代碼,不會關(guān)心子線程什么時候執(zhí)行
System.out.println("main函數(shù)結(jié)束了。");
}
}5.運行ThreadTest.java,觀察結(jié)果,體會多線程的工作原理。

多線程的使用注意事項:有效利用多線程的關(guān)鍵是理解程序是并發(fā)執(zhí)行而不是串行執(zhí)行的。
例如:程序中有兩個子系統(tǒng)需要并發(fā)執(zhí)行,這時候就需要利用多線程編程。通過對多線程的使用,可以編寫出非常高效的程序。
請注意,如果你創(chuàng)建太多的線程,程序執(zhí)行的效率實際上是降低了,而不是提升了。請記住,上下文的切換開銷也很重要,如果你創(chuàng)建了太多的線程,CPU 花費在上下文的切換的時間將多于執(zhí)行程序的時間!
到此這篇關(guān)于Java實現(xiàn)模擬機器人對話的示例代碼的文章就介紹到這了,更多相關(guān)Java 機器人對話內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot3整合Nacos?V2.3.2的詳細過程
本文介紹了如何在?Spring?Boot?3.2.x?項目中整合?Nacos?2.3.2,包括依賴配置、Nacos?服務(wù)發(fā)現(xiàn)與動態(tài)配置的配置方法,通過整合?Nacos,Spring?Boot?應(yīng)用可以實現(xiàn)高效的服務(wù)發(fā)現(xiàn)、動態(tài)配置管理以及分布式系統(tǒng)中的靈活擴展,感興趣的朋友跟隨小編一起看看吧2024-11-11
spring security中Authority、Role的區(qū)別及說明
這篇文章主要介紹了spring security中Authority、Role的區(qū)別及說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-09-09
Java線性結(jié)構(gòu)中的雙向鏈表實現(xiàn)原理
這篇文章將給大家詳細講解雙向鏈表的內(nèi)容,尤其是會通過代碼來進行鏈表的操作,文中的代碼示例介紹的非常詳細,具有一定的參考價值,需要的朋友可以參考下2023-07-07
java實現(xiàn)服務(wù)器文件打包zip并下載的示例(邊打包邊下載)
這篇文章主要介紹了java實現(xiàn)服務(wù)器文件打包zip并下載的示例,使用該方法,可以即時打包文件,一邊打包一邊傳輸,不使用任何的緩存,讓用戶零等待,需要的朋友可以參考下2014-04-04
jdk-logging?log4j?logback日志系統(tǒng)實現(xiàn)機制原理介紹
這篇文章主要介紹了jdk-logging、log4j、logback日志介紹以及三個日志系統(tǒng)的實現(xiàn)機制,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-03-03
Spring Security跳轉(zhuǎn)頁面失敗問題解決
這篇文章主要介紹了Spring Security跳轉(zhuǎn)頁面失敗問題解決,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-01-01
java WebSocket實現(xiàn)聊天消息推送功能
這篇文章主要為大家詳細介紹了java WebSocket實現(xiàn)聊天消息推送功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-07-07
Java輕松掌握面向?qū)ο蟮娜筇匦苑庋b與繼承和多態(tài)
本文主要講述的是面向?qū)ο蟮娜筇匦裕悍庋b,繼承,多態(tài),內(nèi)容含括從封裝到繼承再到多態(tài)的所有重點內(nèi)容以及使用細節(jié)和注意事項,內(nèi)容有點長,請大家耐心看完2022-05-05
Java中EasyPoi導(dǎo)出復(fù)雜合并單元格的方法
這篇文章主要介紹了Java中EasyPoi導(dǎo)出復(fù)雜合并單元格的方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01

