Java線程創(chuàng)建的四種方式總結(jié)
多線程的創(chuàng)建,方式一:繼承于Thread類
1.創(chuàng)建一個(gè)繼承于Thread類的子類
2.重寫Thread類的run()--->將此線程執(zhí)行的操作聲明在run()中
3.創(chuàng)建Thread類的子類的對(duì)象
4.通過(guò)此對(duì)象調(diào)用start():
start()方法的兩個(gè)作用:
A.啟動(dòng)當(dāng)前線程
B.調(diào)用當(dāng)前線程的run()
創(chuàng)建過(guò)程中的兩個(gè)問(wèn)題:
問(wèn)題一:我們不能通過(guò)直接調(diào)用run()的方式啟動(dòng)線程
問(wèn)題二:在啟動(dòng)一個(gè)線程,遍歷偶數(shù),不可以讓已經(jīng)start()的線程去執(zhí)行,會(huì)報(bào)異常;正確的方式是重新創(chuàng)建一個(gè)線程的對(duì)象。
//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類的子類的對(duì)象
MyThread t1 = new MyThread();
//4.通過(guò)此對(duì)象調(diào)用start()
t1.start();
//問(wèn)題一:不能通過(guò)直接調(diào)用run()的方式啟動(dòng)線程
// t1.run();//錯(cuò)誤的
//問(wèn)題二:再啟動(dòng)一個(gè)線程:我們需要再創(chuàng)建 一個(gè)對(duì)象
//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() + ":賣票,票號(hào)為:" + 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)建過(guò)一次對(duì)象,后面就不用了,可以考慮使用匿名類的方式
//創(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)類的對(duì)象
- 將此對(duì)象作為參數(shù)傳遞到Thread類的構(gòu)造器中,創(chuàng)建Thread類的對(duì)象
- 通過(guò)Thread類的對(duì)象調(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)類的對(duì)象
MThread mThread = new MThread();
//4.將此對(duì)象作為參數(shù)傳遞到Thread類的構(gòu)造器中,創(chuàng)建Thread類的對(duì)象
Thread t1 = new Thread(mThread);
t1.setName("線程1");
//5.通過(guò)Thread類的對(duì)象調(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() + "賣票,票號(hào)為:" + ticket);
ticket--;
} else {
break;
}
}
}
}
public class WindowTest {
public static void main(String[] args) {
window1 w = new window1();//只造了一個(gè)對(duì)象,所以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接口
>可以對(duì)具體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)類的對(duì)象
NumThread numThread = new NumThread();
//4.將此Callable接口實(shí)現(xiàn)類的對(duì)象作為參數(shù)傳遞到 FutureTask的構(gòu)造器中,創(chuàng)建FutureTask的對(duì)象
FutureTask futureTask = new FutureTask(numThread);
//5.將 FutureTask的對(duì)象作為參數(shù)傳遞到Thread類的構(gòu)造器中,創(chuàng)建Thread對(duì)象,并調(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ā)情況下的線程,對(duì)性能影響很大。
思路:提前創(chuàng)建好多個(gè)線程,放入線程池中,使用時(shí)直接獲取,使用完放回池中。可以避免頻繁創(chuàng)建銷毀、實(shí)現(xiàn)重復(fù)利用。類似生活中的公共交通工具。
好處:>提高響應(yīng)速度(減少了創(chuàng)建新線程的時(shí)間)
>降低資源消耗(重復(fù)利用線程池中線程,不需要每次都創(chuàng)建)
>便于線程管理:A.corePoolSize:核心池的大小 B.maximumPoolSize:最大線程數(shù) C.keepAliveTime:線程沒(méi)有任務(wù)時(shí)最多保持多長(zhǎng)時(shí)間后會(huì)終止

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)類的對(duì)象
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)的方式更適合來(lái)處理多個(gè)線程有共享數(shù)據(jù)的情況。
系:public class Thread implements Runnable
相同點(diǎn):兩種方式都需要重寫run(),將線程要執(zhí)行的邏輯聲明在run()中

程序(program)是為完成特定任務(wù)、用某種語(yǔ)言編寫的一組指令的集合。即指一段靜態(tài)的代碼,靜態(tài)對(duì)象。
進(jìn)程(process)是程序的一次執(zhí)行過(guò)程,或是正在運(yùn)行的一個(gè)程序。是一個(gè)動(dòng)態(tài)的過(guò)程:有它自身的產(chǎn)生、存在和消亡的過(guò)程。---生命周期
線程(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í),共享的也會(huì)帶來(lái)安全隱患,這就需要我們解決線程安全問(wèn)題
背景:以單核CPU為例,只使用單個(gè)線程先后完成多個(gè)任務(wù)(調(diào)用多個(gè)方法),肯定比用多個(gè)線程來(lái)完成用的時(shí)間更短,為何仍需使用多線程呢?
使用多線程的優(yōu)點(diǎn):
1.提高應(yīng)用程序的響應(yīng)。對(duì)圖形化界面更有意義,可增強(qiáng)用戶體驗(yàn)。
2.提高計(jì)算機(jī)系統(tǒng)CPU的利用率
3.改善程序結(jié)構(gòu)。將即長(zhǎng)又復(fù)雜的線程分為多個(gè)線程,獨(dú)立運(yùn)行,利于理解和修改
何時(shí)需要多線程
1.程序需要同時(shí)執(zhí)行兩個(gè)或多個(gè)任務(wù)。
2.程序需要實(shí)現(xiàn)一些需要等待的任務(wù)時(shí),如用戶輸入、文件讀寫操作、網(wǎng)絡(luò)操作、搜索等。
3.需要一些后臺(tái)運(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í)行路徑,所以是單線程
測(cè)試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ī)會(huì)讓給優(yōu)先級(jí)相同或更高的線程
>若隊(duì)列中沒(méi)有同優(yōu)先級(jí)的線程,忽略此方法
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)。會(huì)拋出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");//通過(guò)構(gòu)造器給線程命名,但前期是得在子類中提供一個(gè)構(gòu)造器
// h1.setName("線程一");
//設(shè)置分線程的優(yōu)先級(jí)
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()的測(cè)試
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
}
}
}
線程的優(yōu)先級(jí):
1.MAX_PRIORITY:10
MIN_PRIORITY:1
NORM_PRIORITY:5--->默認(rèn)優(yōu)先級(jí)
2.如何獲取和設(shè)置當(dāng)前線程的優(yōu)先級(jí):
getPriority():獲取線程的優(yōu)先級(jí)
setPriority(int p):設(shè)置線程的優(yōu)先級(jí)
說(shuō)明:高優(yōu)先級(jí)的線程要搶占低優(yōu)先級(jí)線程CPU的執(zhí)行權(quán),但是只是從概率上講,高優(yōu)先級(jí)的線程高概率的情況下,不一定被執(zhí)行,并不意味著只有當(dāng)高優(yōu)先級(jí)的線程執(zhí)行完畢后,低優(yōu)先級(jí)的線程才執(zhí)行。


到此這篇關(guān)于Java線程創(chuàng)建的四種方式總結(jié)的文章就介紹到這了,更多相關(guān)Java 線程創(chuàng)建內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java的項(xiàng)目構(gòu)建工具M(jìn)aven的配置和使用教程
Maven是Java世界中的項(xiàng)目管理和構(gòu)建自動(dòng)化工具,基于POM項(xiàng)目對(duì)象模型的思想,下面我們就具體來(lái)看一下具體的Java的項(xiàng)目構(gòu)建工具M(jìn)aven的配置和使用教程:2016-05-05
Java 實(shí)戰(zhàn)項(xiàng)目錘煉之網(wǎng)上花店商城的實(shí)現(xiàn)流程
讀萬(wàn)卷書不如行萬(wàn)里路,只學(xué)書上的理論是遠(yuǎn)遠(yuǎn)不夠的,只有在實(shí)戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用java+jsp+servlet+mysql+ajax實(shí)現(xiàn)一個(gè)網(wǎng)上花店商城系統(tǒng),大家可以在過(guò)程中查缺補(bǔ)漏,提升水平2021-11-11
關(guān)于Spring?@Transactional事務(wù)傳播機(jī)制詳解
我們?nèi)粘9ぷ髦袠O少使用事務(wù)傳播級(jí)別,單純只是使用事務(wù)和rollbackfor拋出異常來(lái)解決事務(wù)問(wèn)題,但其實(shí)我們很多時(shí)候使用的是不正確的,或者說(shuō)會(huì)造成事務(wù)粒度過(guò)大,本文詳解一下事務(wù)傳播級(jí)別,也讓自己更好地處理事務(wù)問(wèn)題,需要的朋友可以參考下2023-08-08
Java性能工具JMeter實(shí)現(xiàn)上傳與下載腳本編寫
性能測(cè)試工作中,文件上傳也是經(jīng)常見(jiàn)的性能壓測(cè)場(chǎng)景之一,那么 JMeter 文件上傳下載腳本怎么做,本文詳細(xì)的來(lái)介紹一下,感興趣的可以了解一下2021-07-07
淺談Java中ArrayList的擴(kuò)容機(jī)制
本文主要介紹了淺談Java中ArrayList的擴(kuò)容機(jī)制,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06
Spring Security @PreAuthorize注解分析
本教程介紹了如何使用 Spring 方法級(jí)安全和 @PreAuthorize 注解來(lái)保護(hù) RestController 方法,通過(guò)這些步驟,您可以確保只有具有適當(dāng)角色或權(quán)限的用戶才能訪問(wèn)特定的 REST API,感興趣的朋友跟隨小編一起看看吧2024-11-11

