回 帖 发 新 帖 刷新版面

主题:Java多线程初学者指南 初学必看

一、线程概述

线程是程序运行的基本执行单元。当操作系统(不包括单线程的操作系统,如微软早期的DOS)在执行一个程序时,会在系统中建立一个进程,而在这个进程中,必须至少建立一个线程(这个线程被称为主线程)来作为这个程序运行的入口点。因此,在操作系统中运行的任何程序都至少有一个主线程。

进程和线程是现代操作系统中两个必不可少的运行模型。在操作系统中可以有多个进程,这些进程包括系统进程(由操作系统内部建立的进程)和用户进程(由用户程序建立的进程);一个进程中可以有一个或多个线程。进程和进程之间不共享内存,也就是说系统中的进程是在各自独立的内存空间中运行的。而一个进程中的线可以共享系统分派给这个进程的内存空间。

线程不仅可以共享进程的内存,而且还拥有一个属于自己的内存空间,这段内存空间也叫做线程栈,是在建立线程时由系统分配的,主要用来保存线程内部所使用的数据,如线程执行函数中所定义的变量。

注意:任何一个线程在建立时都会执行一个函数,这个函数叫做线程执行函数。也可以将这个函数看做线程的入口点(类似于程序中的main函数)。无论使用什么语言或技术来建立线程,都必须执行这个函数(这个函数的表现形式可能不一样,但都会有一个这样的函数)。如在Windows中用于建立线程的API函数CreateThread的第三个参数就是这个执行函数的指针。

在操作系统将进程分成多个线程后,这些线程可以在操作系统的管理下并发执行,从而大大提高了程序的运行效率。虽然线程的执行从宏观上看是多个线程同时执行,但实际上这只是操作系统的障眼法。由于一块CPU同时只能执行一条指令,因此,在拥有一块CPU的计算机上不可能同时执行两个任务。而操作系统为了能提高程序的运行效率,在一个线程空闲时会撤下这个线程,并且会让其他的线程来执行,这种方式叫做线程调度。我们之所以从表面上看是多个线程同时执行,是因为不同线程之间切换的时间非常短,而且在一般情况下切换非常频繁。假设我们有线程A和B.在运行时,可能是A执行了1毫秒后,切换到B后,B又执行了1毫秒,然后又切换到了A,A又执行1毫秒。由于1毫秒的时间对于普通人来说是很难感知的,因此,从表面看上去就象A和B同时执行一样,但实际上A和B是交替执行的。

二、线程给我们带来的好处

如果能合理地使用线程,将会减少开发和维护成本,甚至可以改善复杂应用程序的性能。如在GUI应用程序中,还以通过线程的异步特性来更好地处理事件;在应用服务器程序中可以通过建立多个线程来处理客户端的请求。线程甚至还可以简化虚拟机的实现,如Java虚拟机(JVM)的垃圾回收器(garbage collector)通常运行在一个或多个线程中。因此,使用线程将会从以下五个方面来改善我们的应用程序:

1. 充分利用CPU资源

现在世界上大多数计算机只有一块CPU.因此,充分利用CPU资源显得尤为重要。当执行单线程程序时,由于在程序发生阻塞时CPU可能会处于空闲状态。这将造成大量的计算资源的浪费。而在程序中使用多线程可以在某一个线程处于休眠或阻塞时,而CPU又恰好处于空闲状态时来运行其他的线程。这样CPU就很难有空闲的时候。因此,CPU资源就得到了充分地利用。

2. 简化编程模型

如果程序只完成一项任务,那只要写一个单线程的程序,并且按着执行这个任务的步骤编写代码即可。但要完成多项任务,如果还使用单线程的话,那就得在在程序中判断每项任务是否应该执行以及什么时候执行。如显示一个时钟的时、分、秒三个指针。使用单线程就得在循环中逐一判断这三个指针的转动时间和角度。如果使用三个线程分另来处理这三个指针的显示,那么对于每个线程来说就是指行一个单独的任务。这样有助于开发人员对程序的理解和维护。

3. 简化异步事件的处理

当一个服务器应用程序在接收不同的客户端连接时最简单地处理方法就是为每一个客户端连接建立一个线程。然后监听线程仍然负责监听来自客户端的请求。如果这种应用程序采用单线程来处理,当监听线程接收到一个客户端请求后,开始读取客户端发来的数据,在读完数据后,read方法处于阻塞状态,也就是说,这个线程将无法再监听客户端请求了。而要想在单线程中处理多个客户端请求,就必须使用非阻塞的Socket连接和异步I/O.但使用异步I/O方式比使用同步I/O更难以控制,也更容易出错。因此,使用多线程和同步I/O可以更容易地处理类似于多请求的异步事件。

4. 使GUI更有效率

使用单线程来处理GUI事件时,必须使用循环来对随时可能发生的GUI事件进行扫描,在循环内部除了扫描GUI事件外,还得来执行其他的程序代码。如果这些代码太长,那么GUI事件就会被“冻结”,直到这些代码被执行完为止。

在现代的GUI框架(如SWING、AWT和SWT)中都使用了一个单独的事件分派线程(event dispatch thread,EDT)来对GUI事件进行扫描。当我们按下一个按钮时,按钮的单击事件函数会在这个事件分派线程中被调用。由于EDT的任务只是对GUI事件进行扫描,因此,这种方式对事件的反映是非常快的。

5. 节约成本

提高程序的执行效率一般有三种方法:

(1)增加计算机的CPU个数。

(2)为一个程序启动多个进程

(3)在程序中使用多进程。

第一种方法是最容易做到的,但同时也是最昂贵的。这种方法不需要修改程序,从理论上说,任何程序都可以使用这种方法来提高执行效率。第二种方法虽然不用购买新的硬件,但这种方式不容易共享数据,如果这个程序要完成的任务需要必须要共享数据的话,这种方式就不太方便,而且启动多个线程会消耗大量的系统资源。第三种方法恰好弥补了第一种方法的缺点,而又继承了它们的优点。也就是说,既不需要购买CPU,也不会因为启太多的线程而占用大量的系统资源(在默认情况下,一个线程所占的内存空间要远比一个进程所占的内存空间小得多),并且多线程可以模拟多块CPU的运行方式,因此,使用多线程是提高程序执行效率的最廉价的方式。

三、Java的线程模型

由于Java是纯面向对象语言,因此,Java的线程模型也是面向对象的。Java通过Thread类将线程所必须的功能都封装了起来。要想建立一个线程,必须要有一个线程执行函数,这个线程执行函数对应Thread类的run方法。Thread类还有一个start方法,这个方法负责建立线程,相当于调用Windows的建立线程函数CreateThread.当调用start方法后,如果线程建立成功,并自动调用Thread类的run方法。因此,任何继承Thread的Java类都可以通过Thread类的start方法来建立线程。如果想运行自己的线程执行函数,那就要覆盖Thread类的run方法。

在Java的线程模型中除了Thread类,还有一个标识某个Java类是否可作为线程类的接口Runnable,这个接口只有一个抽象方法run,也就是Java线程模型的线程执行函数。因此,一个线程类的唯一标准就是这个类是否实现了Runnable接口的run方法,也就是说,拥有线程执行函数的类就是线程类。

从上面可以看出,在Java中建立线程有两种方法,一种是继承Thread类,另一种是实现Runnable接口,并通过Thread和实现Runnable的类来建立线程,其实这两种方法从本质上说是一种方法,即都是通过Thread类来建立线程,并运行run方法的。但它们的大区别是通过继承Thread类来建立线程,虽然在实现起来更容易,但由于Java不支持多继承,因此,这个线程类如果继承了Thread,就不能再继承其他的类了,因此,Java线程模型提供了通过实现Runnable接口的方法来建立线程,这样线程类可以在必要的时候继承和业务有关的类,而不是Thread类。

QQ 744437114

疯狂软件官网:http://www.fkjava.org

疯狂java视频 android视频:http://www.fkjava.org/video.html

回复列表 (共1个回复)

沙发

最近,因为玉树地震造成的灾害让全国亿万人民都闻之痛心,灾情牵动着每一颗中国人的心,人们从各地纷纷伸出援助之手,帮助灾区人民度过难关,重建家园,于是感动中国的许多人和事都让举国人民为之振奋为之感动,为之流泪……
  很多人很多单位捐款捐物,从国家领导者到普通的中小学生,从明星大婉到打工子弟,不论位置高低赚钱多少,大家都伸出爱的双手为灾区的人民送去温暖擎起一片蓝天。
  也许只有在大灾大难面前才能体会到祖国的博大,人民的团结,爱的力量在此刻才能真正显示出伟大的凝聚力和创造力。
  曾经以为自己只是一个平凡的不能再平凡的人,一个放在哪儿都不起眼的人,可是当我们把自己放在祖国的大家庭里时,放在人们需要的地方时,才发现原来我们每个人的力量都是不可缺少的,只要每个人都献出自己的一份力量,一片爱心,凝聚起来的力量就是不可一视的。
  曹德旺曹晖是这次地震灾义演中给我印象最深刻的父子俩,他们为灾区和西南干旱各捐款一亿,用他们的爱心为灾区人民送去了温暖和真情。让全世界的华人为之钦佩为之感动。
  有良知、有灵魂、有道德、有感情、心系灾区的企业家陈光标,是位高调做慈善的企业家,他希望通过自己的行动弘扬爱国爱民精神让更多的和他一样的富人加入到行善的队伍中来,带动全天下有能力帮助别人的人以各种方式来表达善[url=http://t.sohu.com/u/1412514560]慢性前列腺炎的治疗方法[/url]意。他用行动一次次地感动着中国大地上的每一位善良的人民。
  爱心不仅是捐款捐物的人们还有更多的有识之士,奔向灾区投身到救灾工作中,香港慈善义工阿福其中最感人的一个,从香港到内地,从汶川到玉树,用生命普写了一曲爱之歌……让这个世界永远记住了他的名字!
  才仁旦周是玉树震区志愿者中年龄最小的一个,在这次地震中他成了汉族医生和藏族伤者之间的翻译,因为他特别听话、特别聪明,给医生和受伤的藏族同胞帮上了大忙常常一个人为伤者送水送药,这次震灾义演他到了北京上了中央电视台,用感恩的心让无数[url=http://t.qq.com/szqtzlyw]生殖器图[/url]人为之动容。
  还有许许多多的志愿者,无声的在灾区奉献着自己的爱心,没有人知道他们来自何方,也没有人知道他们的名字,他们用行动默默地谱写着一曲曲爱的奉献!
  大灾无情,人间有爱!祖国的强大,人民的团结,让灾区的人们一次又一次的感受亲情,温暖爱心!
  此时此刻,深深地感[url=http://t.sohu.com/u/1417422940]早泄该怎么治疗[/url]到,我们身为中国人感到无比的欣慰和自豪!
  十三亿中国人只要每个人献出一份爱,灾区的人民就能更多地感受到一份真情,一片爱心。
  没有什么灾难能压倒我们,也没有什么困难不可战胜!中国人民是团结的民族,是伟大的民族,是不可摧毁的力量,相信只要人人都献出一份爱,灾区的人民便能早日脱离困境重建幸福家园!
  [url=http://t.163.com/2097843248]包皮龟头炎的治疗[/url]大灾无情,大爱无边!
  我们每一个中国人都积极地行动起来,为玉树灾区的同胞们献出一份爱!
  玉树加油!青海加油!中国加油!最近,因為玉樹地震造成的災害讓全國億萬人民都聞之痛心,災情牽動著每一顆中國人的心,人們從各地紛紛伸出援助之手,幫助災區人民度過難關,重建傢園,於是感動中國的許多人和事都讓舉國人民為之振奮為之感動,為之流淚……
  很多人很多單位捐款捐物,從國傢領導者到普通的中小學生,從明星大婉到打工子弟,不論位置高低賺錢多少,大傢都伸出愛的雙手為災區的人民送去溫暖擎起一片藍天。
  也許隻有在大災大難面前才能體會到祖國的博大,人民的團結,愛的力量在此刻才能真正顯示出偉大的凝聚力和創造力。
  曾經以為自己隻是一個平凡的不能再平凡的人,一個放在哪兒都[url=http://t.qq.com/ywnxhm]包皮长度[/url]不起眼的人,可是當我們把自己放在祖國的大傢庭裡時,放在人們需要的地方時,才發現原來我們每個人的力量都是[url=http://t.qq.com/qdywzl]轻度阳痿怎么治疗[/url]不可缺少的,隻要每個人都獻出自己的一份力量,一片愛心,凝聚起來的力量就是不可一視的。
  曹德旺曹暉是這次地震災義演中給我印象最深刻的父子倆,他們為災區和西南幹旱各捐款一億,用他們的愛心為災區人民送去瞭溫暖和真情。讓全世界的華人為之欽佩為之感動。
  有良知[url=http://t.sohu.com/u/1424406420]阳萎早泄的治疗[/url]、有靈魂、有道德、有感情、心系災區的企業傢陳光標,是位高調做慈善的企業傢,他希望通過自己的行動弘揚愛國愛民精神讓更多的和他一樣的富人加入到行善的隊伍中來,帶動全天下有能力幫助別人的人以各種方式來表達善意。他用行動一次次地感動著中國大地上的每一位善良的人民。
  愛心不僅是捐款捐物的人們還有更多的有識之士,奔向災區投身到救災工作中,香港慈善義工阿福其中最感人的一個,從香港到內地,從汶川到玉樹,用生命普寫瞭一曲愛之歌……讓這個世界永遠記住瞭他的名字!
  才仁旦周是玉樹震區志願者中年齡最小的一個,在這次地震中他成瞭漢族醫生和藏族傷者之間的翻譯,因為他特別聽話、特別聰明,給醫生和受傷的藏族同胞幫上瞭大忙常常一個人為傷者送水送藥,這次震災義演他到瞭北京上瞭中央電視臺,用感恩的心讓無數人為之動容。
  還有許許多多的志願者,無聲的在災區奉獻著自己的愛心,沒有人知道他們來自何方,也沒有人知道他們的名字,他們用行動默默地譜寫著一曲曲愛的奉獻!
  大災無情,人間有愛!祖國的強大,人民的團結,讓災區的人們一次又一次的感受親情,溫暖愛心!
  此時此刻,深深地感到,我們身為中國人感到無比的欣慰和自豪!
  十三億中國人隻要每個人獻出一份愛,災區的人民就能更多地感受到一份真情,一片愛心。
  沒有什麼災難能壓倒我們,也沒有什麼困難不可戰勝!中國人民是團結的民族,是偉大[url=http://t.qq.com/hwzxqlx]早泄能治好吗[/url]的民族,是不可摧毀的力量,相信隻要人人都獻出一份愛,災區的人民便能早日脫離困境重建幸福傢園!
  大災無情,大愛無邊!
  我們每一個中國人都積極地行動起來,為玉樹災區的同胞們獻出一份愛!
  玉樹加油!青海加油!中國加油!

我来回复

您尚未登录,请登录后再回复。点此登录或注册