Java線程創(chuàng)建的四種方式總結(jié)
多線程的創(chuàng)建,方式一:繼承于Thread類
1.創(chuàng)建一個(gè)繼承于Thread類的子類
2.重寫Thread類的run()--->將此線程執(zhí)行的操作聲明在run()中
3.創(chuàng)建Thread類的子類的對象
4.通過此對象調(diào)用start():
start()方法的兩個(gè)作用:
A.啟動(dòng)當(dāng)前線程
B.調(diào)用當(dāng)前線程的run()
創(chuàng)建過程中的兩個(gè)問題:
問題一:我們不能通過直接調(diào)用run()的方式啟動(dòng)線程
問題二:在啟動(dòng)一個(gè)線程,遍歷偶數(shù),不可以讓已經(jīng)start()的線程去執(zhí)行,會報(bào)異常;正確的方式是重新創(chuàng)建一個(gè)線程的對象。
//1.創(chuàng)建一個(gè)繼承于Thread類的子類
class MyThread extends Thread{
//2.重寫Thread類的run()
@Override
public void run() {//第二個(gè)線程
for(int i = 0;i < 10;i++){
if(i % 2 == 0){
System.out.println(i);
}
}
}
}
public class ThreadTest {
public static void main(String[] args) {//主線程
//3.創(chuàng)建Thread類的子類的對象
MyThread t1 = new MyThread();
//4.通過此對象調(diào)用start()
t1.start();
//問題一:不能通過直接調(diào)用run()的方式啟動(dòng)線程
// t1.run();//錯(cuò)誤的
//問題二:再啟動(dòng)一個(gè)線程:我們需要再創(chuàng)建 一個(gè)對象
//t1.start();//錯(cuò)誤的
MyThread t2 = new MyThread();
t2.start();
for(int i = 0;i < 10;i++){
if(i % 2 != 0){
System.out.println(i + "****main()******");
}
}
}
}
此代碼在主線程內(nèi)輸出奇數(shù),在另一個(gè)線程里輸出偶數(shù),則輸出結(jié)果應(yīng)該是兩個(gè)輸出結(jié)果是交互的。
1****main()******
3****main()******
5****main()******
7****main()******
0
2
4
6
8
9****main()******
class Window extends Thread{//創(chuàng)建三個(gè)窗口賣票, 總票數(shù)為100張,使用繼承于Thread類的方式
private static int ticket = 100;//三個(gè)窗口共享:聲明為static
@Override
public void run() {
while(true){
if(ticket > 0){
System.out.println(getName() + ":賣票,票號為:" + ticket);
ticket--;
}else{
break;
}
}
}
}
public class WindowTest2 {
public static void main(String[] args) {
Window t1 = new Window();
Window t2 = new Window();
Window t3 = new Window();
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
public class ThreadDemo {
public static void main(String[] args) {
// MyThread1 m1 = new MyThread1();
// MyThread2 m2 = new MyThread2();
// m1.start();
// m2.start();
//由于造的類只創(chuàng)建過一次對象,后面就不用了,可以考慮使用匿名類的方式
//創(chuàng)建Thread類的匿名子類的方式
new Thread(){
@Override
public void run() {
for(int i = 0;i < 100;i++){
if(i % 2 == 0){
System.out.println(i);
}
}
}
}.start();
new Thread(){
@Override
public void run() {
for(int i = 0;i < 100;i++){
if(i % 2 != 0){
System.out.println(i);
}
}
}
}.start();
}
}
class MyThread1 extends Thread{
@Override
public void run() {
for(int i = 0;i < 100;i++){
if(i % 2 == 0){
System.out.println(i);
}
}
}
}
class MyThread2 extends Thread{
@Override
public void run() {
for(int i = 0;i < 100;i++){
if(i % 2 != 0){
System.out.println(i);
}
}
}
}
創(chuàng)建多線程的方式二:實(shí)現(xiàn)Runnable接口
- 創(chuàng)建一個(gè)實(shí)現(xiàn)了Runnable接口的類
- 實(shí)現(xiàn)類去實(shí)現(xiàn)Runnable中的抽象方法:run()
- 創(chuàng)建實(shí)現(xiàn)類的對象
- 將此對象作為參數(shù)傳遞到Thread類的構(gòu)造器中,創(chuàng)建Thread類的對象
- 通過Thread類的對象調(diào)用start()
class MThread implements Runnable{
//2.實(shí)現(xiàn)類去實(shí)現(xiàn)Runnable中的抽象方法:run()
@Override
public void run() {
for(int i = 0;i < 100;i++){
if (i % 2 == 0) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
}
public class ThreadTest1 {
public static void main(String[] args) {
//3.創(chuàng)建實(shí)現(xiàn)類的對象
MThread mThread = new MThread();
//4.將此對象作為參數(shù)傳遞到Thread類的構(gòu)造器中,創(chuàng)建Thread類的對象
Thread t1 = new Thread(mThread);
t1.setName("線程1");
//5.通過Thread類的對象調(diào)用start():A.啟動(dòng)線程B.調(diào)用當(dāng)前線程的run()-->調(diào)用了Runnable類型的target
t1.start();
//再啟動(dòng)一個(gè)線程,遍歷100以內(nèi)的偶數(shù)//只需重新實(shí)現(xiàn)步驟4,5即可
Thread t2 = new Thread(mThread);
t2.setName("線程2");
t2.start();
}
}
class window1 implements Runnable{//創(chuàng)建三個(gè)窗口賣票, 總票數(shù)為100張,使用實(shí)現(xiàn)Runnable接口的方式
private int ticket = 100;
Object obj = new Object();
@Override
public void run() {
while (true){
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "賣票,票號為:" + ticket);
ticket--;
} else {
break;
}
}
}
}
public class WindowTest {
public static void main(String[] args) {
window1 w = new window1();//只造了一個(gè)對象,所以100張票共享
Thread t1 = new Thread(w);
Thread t2 = new Thread(w);
Thread t3 = new Thread(w);
t1.setName("線程1");
t2.setName("線程2");
t3.setName("線程3");
t1.start();
t2.start();
t3.start();
}
}
創(chuàng)建線程的方式三:實(shí)現(xiàn)Callable接口---JDK5.0新增
與使用Runnable相比,Callable功能更強(qiáng)大些
>相比run()方法,可以有返回值
>方法可以拋出異常
>支持泛型的返回值
>需要借助FutureTask類,比如獲取返回結(jié)果
Future接口
>可以對具體Runnable、Callable任務(wù)的執(zhí)行結(jié)果進(jìn)行取消、查詢是否完成、獲取結(jié)果等。
>FutureTask是Futrue接口的唯一的實(shí)現(xiàn)類
>FutureTaskb同時(shí)實(shí)現(xiàn)了Runnable,Future接口。它既可以作為Runnable被線程執(zhí)行,又可以作為Future得到Callable的返回值
//1.創(chuàng)建一個(gè)實(shí)現(xiàn)Callable的實(shí)現(xiàn)類
class NumThread implements Callable{
//2.實(shí)現(xiàn)call方法,將此線程需要執(zhí)行的操作聲明在call()中
@Override
public Object call() throws Exception {
int sum = 0;
for(int i = 1;i <= 100;i++){
if(i % 2 == 0){
System.out.println(i);
sum += i;
}
}
return sum;//sum是int,自動(dòng)裝箱為Integer(Object的子類)
}
}
public class ThreadNew {
public static void main(String[] args) {
//3.創(chuàng)建Callable接口實(shí)現(xiàn)類的對象
NumThread numThread = new NumThread();
//4.將此Callable接口實(shí)現(xiàn)類的對象作為參數(shù)傳遞到 FutureTask的構(gòu)造器中,創(chuàng)建FutureTask的對象
FutureTask futureTask = new FutureTask(numThread);
//5.將 FutureTask的對象作為參數(shù)傳遞到Thread類的構(gòu)造器中,創(chuàng)建Thread對象,并調(diào)用start()
new Thread(futureTask).start();
try {
//獲取Callable中call()的返回值(不是必須的步驟)
//get()返回值即為FutureTask構(gòu)造器參數(shù)Callable實(shí)現(xiàn)類重寫的call()的返回值。
Object sum = futureTask.get();
System.out.println("總和為:" + sum);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
創(chuàng)建線程的方式四:使用線程池--->JDK5.0新增
背景:經(jīng)常創(chuàng)建和銷毀、使用量特別大的資源,比如并發(fā)情況下的線程,對性能影響很大。
思路:提前創(chuàng)建好多個(gè)線程,放入線程池中,使用時(shí)直接獲取,使用完放回池中??梢员苊忸l繁創(chuàng)建銷毀、實(shí)現(xiàn)重復(fù)利用。類似生活中的公共交通工具。
好處:>提高響應(yīng)速度(減少了創(chuàng)建新線程的時(shí)間)
>降低資源消耗(重復(fù)利用線程池中線程,不需要每次都創(chuàng)建)
>便于線程管理:A.corePoolSize:核心池的大小 B.maximumPoolSize:最大線程數(shù) C.keepAliveTime:線程沒有任務(wù)時(shí)最多保持多長時(shí)間后會終止

class NumberThread implements Runnable{
@Override
public void run() {
for(int i = 0;i <= 100;i++){
if(i % 2 == 0){
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
}
class NumberThread1 implements Runnable{
@Override
public void run() {
for(int i = 0;i <= 100;i++){
if(i % 2 != 0){
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
}
public class ThreadPool {
public static void main(String[] args) {
//1.提供指定線程數(shù)量的線程池
ExecutorService service = Executors.newFixedThreadPool(10);
ThreadPoolExecutor service1 = (ThreadPoolExecutor) service;
//設(shè)置線程池的屬性
// System.out.println(service.getClass());
// service1.setCorePoolSize(15);
// service1.setKeepAliveTime();
//2.執(zhí)行指定的線程操作。需要提供實(shí)現(xiàn)Runnable 接口或Callable接口實(shí)現(xiàn)類的對象
service.execute(new NumberThread());//適用于Runnable
service.execute(new NumberThread1());//適用于Runnable
// service.submit(Callable callable);//適用于Callable
//3.關(guān)閉連接池
service.shutdown();
}
}
比較創(chuàng)建線程的兩種方式:
開發(fā)中:優(yōu)先選擇:實(shí)現(xiàn)Runnable接口的方式
原因:1.實(shí)現(xiàn)的方式?jīng)]有類的單繼承性的局限性
2.實(shí)現(xiàn)的方式更適合來處理多個(gè)線程有共享數(shù)據(jù)的情況。
系:public class Thread implements Runnable
相同點(diǎn):兩種方式都需要重寫run(),將線程要執(zhí)行的邏輯聲明在run()中

程序(program)是為完成特定任務(wù)、用某種語言編寫的一組指令的集合。即指一段靜態(tài)的代碼,靜態(tài)對象。
進(jìn)程(process)是程序的一次執(zhí)行過程,或是正在運(yùn)行的一個(gè)程序。是一個(gè)動(dòng)態(tài)的過程:有它自身的產(chǎn)生、存在和消亡的過程。---生命周期
線程(thread),進(jìn)程可進(jìn)一步細(xì)化為線程,是一個(gè)程序內(nèi)部的一條執(zhí)行路徑。

線程作為調(diào)度和執(zhí)行的單位,每個(gè)線程擁有獨(dú)立的運(yùn)行棧和計(jì)數(shù)器,每個(gè)進(jìn)程擁有獨(dú)立的方法區(qū)和堆;意味著,多個(gè)線程共享一個(gè)方法區(qū)和堆。而共享的就可以優(yōu)化,同時(shí),共享的也會帶來安全隱患,這就需要我們解決線程安全問題
背景:以單核CPU為例,只使用單個(gè)線程先后完成多個(gè)任務(wù)(調(diào)用多個(gè)方法),肯定比用多個(gè)線程來完成用的時(shí)間更短,為何仍需使用多線程呢?
使用多線程的優(yōu)點(diǎn):
1.提高應(yīng)用程序的響應(yīng)。對圖形化界面更有意義,可增強(qiáng)用戶體驗(yàn)。
2.提高計(jì)算機(jī)系統(tǒng)CPU的利用率
3.改善程序結(jié)構(gòu)。將即長又復(fù)雜的線程分為多個(gè)線程,獨(dú)立運(yùn)行,利于理解和修改
何時(shí)需要多線程
1.程序需要同時(shí)執(zhí)行兩個(gè)或多個(gè)任務(wù)。
2.程序需要實(shí)現(xiàn)一些需要等待的任務(wù)時(shí),如用戶輸入、文件讀寫操作、網(wǎng)絡(luò)操作、搜索等。
3.需要一些后臺運(yùn)行的程序時(shí)。
public class Sample{
public void method1(String str){
System.out.println(str);
}
public void method2(String str){
method1(str);
}
public static void main(String[] args){
Sample s = new Sample();
s.method2("hello!");
}
}
注意:此程序不是多線程!main方法中調(diào)用了method1,method1中又調(diào)用了method2;是一條執(zhí)行路徑,所以是單線程
測試Thread類的常用方法:
1.start():啟動(dòng)當(dāng)前線程:調(diào)用當(dāng)前線程的run()
2.run():通常需要重寫Thread類中的此方法,將創(chuàng)建的線程要執(zhí)行的操作聲明在此方法中
3.currentThread():靜態(tài)方法,返回執(zhí)行當(dāng)前代碼的線程
4.getName():獲取當(dāng)前線程的名字
5.setName():設(shè)置當(dāng)前線程的名字
6.yield():釋放當(dāng)前CPU的執(zhí)行權(quán)(下一刻CPU執(zhí)行的線程仍是隨機(jī)的)
>暫停當(dāng)前正在執(zhí)行的線程,把執(zhí)行機(jī)會讓給優(yōu)先級相同或更高的線程
>若隊(duì)列中沒有同優(yōu)先級的線程,忽略此方法
7.join():在線程a中調(diào)用線程b的join(),此時(shí),線程a就進(jìn)入阻塞狀態(tài)(停止執(zhí)行),直到線程b完全執(zhí)行完以后,線程b才結(jié)束阻塞狀態(tài)(開始執(zhí)行)。
8.sleep(long millitime):讓當(dāng)前線程"睡眠"指定的millitime毫秒。在指定的millitime毫秒時(shí)間內(nèi),當(dāng)前線程是阻塞狀態(tài)。會拋出InterruptedException異常
* 9.isAlive():判斷當(dāng)前線程是否存活
class HelloThread extends Thread{
@Override
public void run() {
for(int i = 0;i < 100;i++){
if(i % 2 != 0){
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":" +Thread.currentThread().getPriority() + ":" + i);
}
}
}
public HelloThread(String name){
super(name);
}
}
public class ThreadMethodTest {
public static void main(String[] args) {
HelloThread h1 = new HelloThread("Thread:1");//通過構(gòu)造器給線程命名,但前期是得在子類中提供一個(gè)構(gòu)造器
// h1.setName("線程一");
//設(shè)置分線程的優(yōu)先級
h1.setPriority(Thread.MAX_PRIORITY);
h1.start();
//給主線程命名
Thread.currentThread().setName("主線程");
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
for(int i = 0;i < 100;i++){
if(i % 2 == 0) {
System.out.println(Thread.currentThread().getName() + ":" + Thread.currentThread().getPriority() + ":" + i);
}
// if(i == 20){
// try {
// h1.join();//join()的測試
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
}
}
}
線程的優(yōu)先級:
1.MAX_PRIORITY:10
MIN_PRIORITY:1
NORM_PRIORITY:5--->默認(rèn)優(yōu)先級
2.如何獲取和設(shè)置當(dāng)前線程的優(yōu)先級:
getPriority():獲取線程的優(yōu)先級
setPriority(int p):設(shè)置線程的優(yōu)先級
說明:高優(yōu)先級的線程要搶占低優(yōu)先級線程CPU的執(zhí)行權(quán),但是只是從概率上講,高優(yōu)先級的線程高概率的情況下,不一定被執(zhí)行,并不意味著只有當(dāng)高優(yōu)先級的線程執(zhí)行完畢后,低優(yōu)先級的線程才執(zhí)行。


到此這篇關(guān)于Java線程創(chuàng)建的四種方式總結(jié)的文章就介紹到這了,更多相關(guān)Java 線程創(chuàng)建內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MybatisPlus自帶的queryWrapper實(shí)現(xiàn)時(shí)間倒序方式
這篇文章主要介紹了MybatisPlus自帶的queryWrapper實(shí)現(xiàn)時(shí)間倒序方式,具有很好的參考價(jià)值,希望對的有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01
SpringMVC通過Ajax處理Json數(shù)據(jù)的步驟詳解
這篇文章主要介紹了SpringMVC通過Ajax處理Json數(shù)據(jù)的步驟詳解,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04
如何在Java中調(diào)用python文件執(zhí)行詳解
豐富的第三方庫使得python非常適合用于進(jìn)行數(shù)據(jù)分析,最近在項(xiàng)目中就涉及到j(luò)ava調(diào)用python實(shí)現(xiàn)的算法,下面這篇文章主要給大家介紹了關(guān)于如何在Java中調(diào)用python文件執(zhí)行的相關(guān)資料,需要的朋友可以參考下2022-05-05
關(guān)于@RequestBody和@RequestParam注解的使用詳解
這篇文章主要介紹了關(guān)于@RequestBody和@RequestParam注解的使用詳解,本文十分具有參考意義,希望可以幫助到你,如果有錯(cuò)誤的地方還望不吝賜教2023-03-03
Java基本概念監(jiān)視器實(shí)習(xí)原理解析
這篇文章主要介紹了Java基本概念監(jiān)視器實(shí)習(xí)原理解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08
SpringBoot基于Disruptor實(shí)現(xiàn)高效的消息隊(duì)列?
Disruptor是一個(gè)開源的Java框架,它被設(shè)計(jì)用于在生產(chǎn)者-消費(fèi)者問題上獲得盡量高的吞吐量和盡量低的延遲,本文主要介紹了SpringBoot基于Disruptor實(shí)現(xiàn)高效的消息隊(duì)列?,具有一定的參考價(jià)值,感興趣的可以了解一下2024-02-02
徹底理解Spring注解@Autowired實(shí)現(xiàn)原理
這篇文章主要為大家詳細(xì)的介紹了Spring注解@Autowired實(shí)現(xiàn)的原理,縝密的邏輯分析,實(shí)踐應(yīng)用示例操作說明,讓大家徹底的理解Spring注解@Autowired背后實(shí)現(xiàn)原理2022-03-03
Mybatis以main方法形式調(diào)用dao層執(zhí)行代碼實(shí)例
這篇文章主要介紹了Mybatis以main方法形式調(diào)用dao層執(zhí)行代碼實(shí)例,MyBatis 是一款優(yōu)秀的持久層框架,MyBatis 免除了幾乎所有的 JDBC 代碼以及設(shè)置參數(shù)和獲取結(jié)果集的工作,需要的朋友可以參考下2023-08-08
Spring Security 密碼驗(yàn)證動(dòng)態(tài)加鹽的驗(yàn)證處理方法
小編最近在改造項(xiàng)目,需要將gateway整合security在一起進(jìn)行認(rèn)證和鑒權(quán),今天小編給大家分享Spring Security 密碼驗(yàn)證動(dòng)態(tài)加鹽的驗(yàn)證處理方法,感興趣的朋友一起看看吧2021-06-06

