电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

淺析 Java多線程

瀏覽:33日期:2022-08-23 17:41:44

什么是進(jìn)程

當(dāng)一個(gè)程序進(jìn)入內(nèi)存中運(yùn)行起來它就變?yōu)橐粋€(gè)進(jìn)程。因此,進(jìn)程就是一個(gè)處于運(yùn)行狀態(tài)的程序。同時(shí)進(jìn)程具有獨(dú)立功能,進(jìn)程是操作系統(tǒng)進(jìn)行資源分配和調(diào)度的獨(dú)立單位。

什么是線程

線程是進(jìn)程的組成部分。通常情況下,一個(gè)進(jìn)程可擁有多個(gè)線程,而一個(gè)線程只能擁有一個(gè)父進(jìn)程。

線程可以擁有自己的堆棧、自己的程序計(jì)數(shù)器及自己的局部變量,但是線程不能擁有系統(tǒng)資源,它與其父進(jìn)程的其他線程共享進(jìn)程中的全部資源,這其中包括進(jìn)程的代碼段、數(shù)據(jù)段、堆空間以及一些進(jìn)程級(jí)的資源(例如,打開的文件等)。

線程是進(jìn)程的執(zhí)行單元,是CPU調(diào)度和分派的基本單位,當(dāng)進(jìn)程被初始化之后,主線程就會(huì)被創(chuàng)建。同時(shí)如果有需要,還可以在程序執(zhí)行過程中創(chuàng)建出其他線程,這些線程之間也是相互獨(dú)立的,并且在同一進(jìn)程中并發(fā)執(zhí)行。因此一個(gè)進(jìn)程中可以包含多個(gè)線程,但是至少要包含一個(gè)線程,即主線程。

淺析 Java多線程

Java中的線程

Java 中使用Thread類表示一個(gè)線程。所有的線程對(duì)象都必須是Thread或其子類的對(duì)象。Thread 類中的 run 方法是該線程的執(zhí)行代碼。讓我們來看一個(gè)實(shí)例:

public class Ticket extends Thread{ // 重寫run方法 public void run() { for (int i = 0; i < 20; i++) { System.out.println(getName() + ': ' + i); } }}

public class TestThread { public static void main(String[] args) { // 1.創(chuàng)建線程 Thread thread1 = new Ticket(); Thread thread2 = new Ticket();// 2.啟動(dòng)線程 thread1.start(); thread2.start(); }}

運(yùn)行結(jié)果如下:

淺析 Java多線程

 通過上面的代碼和運(yùn)行結(jié)果,我們可以得到:

線程運(yùn)行的幾個(gè)特點(diǎn)

1.同一進(jìn)程下不同線程的調(diào)度不由程序控制。線程的執(zhí)行是搶占式的,運(yùn)行的順序和線程的啟動(dòng)順序是無關(guān)的,當(dāng)前運(yùn)行的線程隨時(shí)都可能被掛起,然后其他進(jìn)程搶占運(yùn)行。

2.線程獨(dú)享自己的堆棧程序計(jì)數(shù)器和局部變量。兩個(gè)進(jìn)程的局部變量互不干擾,各自的執(zhí)行順序也是互不干擾。

3.兩個(gè)線程并發(fā)執(zhí)行。兩個(gè)線程同時(shí)向前推進(jìn),并沒有說執(zhí)行完一個(gè)后再執(zhí)行另一個(gè)。

start()方法和run()方法

啟動(dòng)一個(gè)線程必須調(diào)用Thread 類的 start()方法,使該線程處于就緒狀態(tài),這樣該線程就可以被處理器調(diào)度。

run()方法是一個(gè)線程所關(guān)聯(lián)的執(zhí)行代碼,無論是派生自 Thread類的線程類,還是實(shí)現(xiàn)Runnable接口的類,都必須實(shí)現(xiàn)run()方法,run()方法里是我們需要線程所執(zhí)行的代碼。

實(shí)現(xiàn)多線程必須調(diào)用Thread 類的 start()方法來啟動(dòng)線程,使線程處于就緒狀態(tài)隨時(shí)供CPU調(diào)度。如果直接調(diào)用run()方法的話,只是調(diào)用了Thread類的一個(gè)普通方法,會(huì)立即執(zhí)行該方法中的代碼,并沒有實(shí)現(xiàn)多線程技術(shù)。

Java中多線程的實(shí)現(xiàn)方法

在Java中有三種方法實(shí)現(xiàn)多線程。

第一種方法:使用Thread類或者使用一個(gè)派生自Thread 類的類構(gòu)建一個(gè)線程。

第二種方法:實(shí)現(xiàn)Runnable 接口來構(gòu)建一個(gè)線程。(推薦使用)

第三種方法:實(shí)現(xiàn)Callable 接口來構(gòu)建一個(gè)線程。(有返回值)

第一種方法

使用Thread類或者使用一個(gè)派生自Thread 類的類構(gòu)建一個(gè)線程。

public class Ticket extends Thread{ // 重寫run方法 public void run() { for (int i = 0; i < 20; i++) { System.out.println(getName() + ': ' + i); } }}

public class TestThread { public static void main(String[] args) { // 1.創(chuàng)建線程 Thread thread1 = new Ticket(); Thread thread2 = new Ticket();// 2.啟動(dòng)線程 thread1.start(); thread2.start(); }}

看上面的代碼,我們創(chuàng)建了一個(gè)Ticket類,它繼承了Thread類,重寫了Thread類的run方法。然后我們用Ticket類創(chuàng)建了兩個(gè)線程,并且啟動(dòng)了它們。但我們不推薦使用這種方法,因?yàn)橐粋€(gè)類繼承了Thread類,那它就沒有辦法繼承其他類了,這對(duì)較為復(fù)雜的程序開發(fā)是不利的。

第二種方法

實(shí)現(xiàn)Runnable 接口來構(gòu)建一個(gè)線程。

public class Ticket implements Runnable{ // 重寫run方法 public void run() { for (int i = 0; i < 20; i++) { System.out.println(Thread.currentThread().getName() + ': ' + i); } }}

public class TestThread { public static void main(String[] args) { // 1.創(chuàng)建線程 Ticket t1 = new Ticket(); Ticket t2 = new Ticket(); Thread thread1 = new Thread(t1, '買票1號(hào)'); Thread thread2 = new Thread(t2, '買票2號(hào)');// 2.啟動(dòng)線程 thread1.start(); thread2.start(); }}

我們創(chuàng)建了一個(gè)Ticket類,實(shí)現(xiàn)了Runnable接口,在該類中實(shí)現(xiàn)了run方法。在啟動(dòng)線程前,我們要?jiǎng)?chuàng)建一個(gè)線程對(duì)象,不同的是我們要將一個(gè)實(shí)現(xiàn)了Runnable接口的類的對(duì)象作為Thread類構(gòu)造方法的參數(shù)傳入,以構(gòu)建線程對(duì)象。構(gòu)造方法Thread的第二個(gè)參數(shù)用來指定該線程的名字,通過Thread.currentThread().getName()可獲取當(dāng)前線程的名字。

在真實(shí)的項(xiàng)目開發(fā)中,推薦使用實(shí)現(xiàn)Runnable接口的方法進(jìn)行多線程編程。因?yàn)檫@樣既可以實(shí)現(xiàn)一個(gè)線程的功能,又可以更好地復(fù)用其他類的屬性和方法。

第三種方法

實(shí)現(xiàn)Callable 接口來構(gòu)建一個(gè)線程。

public class TestThread { public static void main(String[] args) { // 1.創(chuàng)建Callable的實(shí)例 Callable<String> callable = new Callable<String>() { @Override public String call() throws Exception {Thread.sleep(7000);return '我結(jié)束了'; } };// 2.通過FutureTask接口的實(shí)例包裝Callable的實(shí)例 FutureTask<String> futureTask = new FutureTask<String>(callable);// 3.創(chuàng)建線程并啟動(dòng) new Thread(futureTask).start();// 4.獲得結(jié)果并打印 try { System.out.println(futureTask.get()); } catch (Exception e) { e.printStackTrace(); } }}

首先我們用匿名內(nèi)部類創(chuàng)建了一個(gè)實(shí)現(xiàn)Callable接口的類的對(duì)象,然后通過FutureTask 的實(shí)例包裝了Callable的實(shí)例,這樣我們就可以通過一個(gè)Thread 對(duì)象在新線程中執(zhí)行call()方法,同時(shí)又可以通過get方法獲取到call()的返回值。然后創(chuàng)建線程并啟動(dòng)它,最后在線程執(zhí)行完執(zhí)行完call()方法后得到返回值并打印。

我們來看一下Callable的源碼:

public interface Callable<V> { /** * Computes a result, or throws an exception if unable to do so. * * @return computed result * @throws Exception if unable to compute a result */ V call() throws Exception;}

從Callable 的定義可以看出,Callable接口是一個(gè)泛型接口,它定義的call()方法類似于Runnable 的run()方法,是線程所關(guān)聯(lián)的執(zhí)行代碼。但是與run()方法不同的是,call()方法具有返回值,并且泛型接口的參數(shù)V指定了call()方法的返回值類型。同時(shí),如果call()方法得不到返回值將會(huì)拋出一個(gè)異常,而在Runnable的run()方法中不能拋出異常。

如何獲得call()方法的返回值

通過Future接口來獲取。Future接口定義了一組對(duì) Runnable 或者Callable 任務(wù)的執(zhí)行結(jié)果進(jìn)行取消、查詢、獲取、設(shè)置的操作。其中g(shù)et方法用于獲取call()的返回值,它會(huì)發(fā)生阻塞,直到call()返回結(jié)果。

這樣的線程調(diào)用與直接同步調(diào)用函數(shù)有什么差異

在上面的例子中,通過future.get()獲取 call()的返回值時(shí),由于call方法中會(huì) sleep 7s,所以在執(zhí)行future.get()的時(shí)候主線程會(huì)被阻塞而什么都不做,等待call()執(zhí)行完并得到返回值。但是這與直接調(diào)用函數(shù)獲取返回值還是有本質(zhì)區(qū)別的。

因?yàn)閏all()方法是運(yùn)行在其他線程里的,在這個(gè)過程中主線程并沒有被阻塞,還是可以做其他事情的,除非執(zhí)行future.get()去獲取 call()的返回值時(shí)主線程才會(huì)被阻塞。所以當(dāng)調(diào)用了Thread.start()方法啟動(dòng) Callable 線程后主線程可以執(zhí)行別的工作,當(dāng)需要call()的返回值時(shí)再去調(diào)用future.get()獲取,此時(shí)call()方法可能早已執(zhí)行完畢,這樣就可以既確保耗時(shí)操作在工作線程中完成而不阻擋主線程,又可以得到線程執(zhí)行結(jié)果的返回值。而直接調(diào)用函數(shù)獲取返回值是一個(gè)同步操作,該函數(shù)本身就是運(yùn)行在主線程中,所以一旦函數(shù)中有耗時(shí)操作,必然會(huì)阻擋主線程。

以上就是淺析 Java多線程的詳細(xì)內(nèi)容,更多關(guān)于Java多線程的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 大倾角皮带机-皮带输送机-螺旋输送机-矿用皮带输送机价格厂家-河南坤威机械 | 超声波分散机-均质机-萃取仪-超声波涂料分散设备-杭州精浩 | 防爆电机_ybx3系列电机_河南省南洋防爆电机有限公司 | 杭州用友|用友软件|用友财务软件|用友ERP系统--杭州协友软件官网 | 精密模具-双色注塑模具加工-深圳铭洋宇通 | 专业深孔加工_东莞深孔钻加工_东莞深孔钻_东莞深孔加工_模具深孔钻加工厂-东莞市超耀实业有限公司 | 北京晚会活动策划|北京节目录制后期剪辑|北京演播厅出租租赁-北京龙视星光文化传媒有限公司 | 沥青灌缝机_路面灌缝机_道路灌缝机_沥青灌缝机厂家_济宁萨奥机械有限公司 | 南京办公用品网-办公文具用品批发-打印机耗材采购 | 冷水机-工业冷水机-冷水机组-欧科隆品牌保障 | 火锅加盟_四川成都火锅店加盟_中国火锅连锁品牌十强_朝天门火锅【官网】 | 精密钢管,冷拔精密无缝钢管,精密钢管厂,精密钢管制造厂家,精密钢管生产厂家,山东精密钢管厂家 | 衬氟止回阀_衬氟闸阀_衬氟三通球阀_衬四氟阀门_衬氟阀门厂-浙江利尔多阀门有限公司 | VOC检测仪-甲醛检测仪-气体报警器-气体检测仪厂家-深恒安科技有限公司 | 针焰试验仪,灼热丝试验仪,漏电起痕试验仪,水平垂直燃烧试验仪 - 苏州亚诺天下仪器有限公司 | 河南不锈钢水箱_地埋水箱_镀锌板水箱_消防水箱厂家-河南联固供水设备有限公司 | 浙江浩盛阀门有限公司 | 轴承振动测量仪电箱-轴承测振动仪器-测试仪厂家-杭州居易电气 | 卡诺亚轻高定官网_卧室系统_整家定制_定制家居_高端定制_全屋定制加盟_定制家具加盟_定制衣柜加盟 | 贵阳用友软件,贵州财务软件,贵阳ERP软件_贵州优智信息技术有限公司 | 北京亦庄厂房出租_经开区产业园招商信息平台 | 【直乐】河北石家庄脊柱侧弯医院_治疗椎间盘突出哪家医院好_骨科脊柱外科专业医院_治疗抽动症/关节病骨伤权威医院|排行-直乐矫形中医医院 | 二手电脑回收_二手打印机回收_二手复印机回_硒鼓墨盒回收-广州益美二手电脑回收公司 | 全自动端子机|刺破式端子压接机|全自动双头沾锡机|全自动插胶壳端子机-东莞市傅氏兄弟机械设备有限公司 | 厦门ISO认证|厦门ISO9001认证|厦门ISO14001认证|厦门ISO45001认证-艾索咨询专注ISO认证行业 | 脉冲除尘器,除尘器厂家-淄博机械| 东莞猎头公司_深圳猎头公司_广州猎头公司-广东万诚猎头提供企业中高端人才招聘服务 | 济南ISO9000认证咨询代理公司,ISO9001认证,CMA实验室认证,ISO/TS16949认证,服务体系认证,资产管理体系认证,SC食品生产许可证- 济南创远企业管理咨询有限公司 郑州电线电缆厂家-防火|低压|低烟无卤电缆-河南明星电缆 | 广州冷却塔维修厂家_冷却塔修理_凉水塔风机电机填料抢修-广东康明节能空调有限公司 | 托盘租赁_塑料托盘租赁_托盘出租_栈板出租_青岛托盘租赁-优胜必达 | 猪I型/II型胶原-五克隆合剂-细胞冻存培养基-北京博蕾德科技发展有限公司 | 电采暖锅炉_超低温空气源热泵_空气源热水器-鑫鲁禹电锅炉空气能热泵厂家 | 品牌广告服务平台,好排名,好流量,好生意。| 生物除臭剂-除味剂-植物-污水除臭剂厂家-携葵环保有限公司 | 微量水分测定仪_厂家_卡尔费休微量水分测定仪-淄博库仑 | 涿州网站建设_网站设计_网站制作_做网站_固安良言多米网络公司 | 上海公众号开发-公众号代运营公司-做公众号的公司企业服务商-咏熠软件 | 天津仓库出租网-天津电商仓库-天津云仓一件代发-【博程云仓】 | 电地暖-电采暖-发热膜-石墨烯电热膜品牌加盟-暖季地暖厂家 | GEDORE扭力螺丝刀-GORDON防静电刷-CHEMTRONICS吸锡线-上海卓君电子有限公司 | 雷蒙磨,雷蒙磨粉机,雷蒙磨机 - 巩义市大峪沟高峰机械厂 |