Java程序员必须掌握的线程知识(精选五篇)

时间:2019-05-12 20:23:40下载本文作者:会员上传
简介:写写帮文库小编为你整理了多篇相关的《Java程序员必须掌握的线程知识》,但愿对你工作学习有帮助,当然你在写写帮文库还可以找到更多《Java程序员必须掌握的线程知识》。

第一篇:Java程序员必须掌握的线程知识

Java程序员必须掌握的线程知识 Callable和Future Callable和Future出现的原因

创建线程的2种方式,一种是直接继承Thread,另外一种就是实现Runnable接口。

这2种方式都有一个缺陷就是:在执行完任务之后无法获取执行结果。如果需要获取执行结果,就必须通过共享变量或者使用线程通信的方式来达到效果,这样使用起来就比较麻烦。

而自从Java 1.5开始,就提供了Callable和Future,通过它们可以在任务执行完毕之后得到任务执行结果。

Callable和Future介绍

Callable接口代表一段可以调用并返回结果的代码;Future接口表示异步任务,是还没有完成的任务给出的未来结果。所以说Callable用于产生结果,Future用于获取结果。

Callable接口使用泛型去定义它的返回类型。Executors类提供了一些有用的方法在线程池中执行Callable内的任务。由于Callable任务是并行的(并行就是整体看上去是并行的,其实在某个时间点只有一个线程在执行),我们必须等待它返回的结果。

java.util.concurrent.Future对象为我们解决了这个问题。在线程池提交Callable任务后返回了一个Future对象,使用它可以知道Callable任务的状态和得到Callable返回的执行结果。Future提供了get()方法让我们可以等待Callable结束并获取它的执行结果。

Callable与Runnable

java.lang.Runnable吧,它是一个接口,在它里面只声明了一个run()方法:

publicinterfaceRunnable{

publicabstractvoid run();}

由于run()方法返回值为void类型,所以在执行完任务之后无法返回任何结果。

Callable位于java.util.concurrent包下,它也是一个接口,在它里面也只声明了一个方法,只不过这个方法叫做call():

publicinterfaceCallable{

/**

* 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()throwsException;}

可以看到,这是一个泛型接口,call()函数返回的类型就是传递进来的V类型。

那么怎么使用Callable呢?

一般情况下是配合ExecutorService来使用的,在ExecutorService接口中声明了若干个submit方法的重载版本:

Future submit(Callable task); Future submit(Runnable task, T result);Future submit(Runnable task);

第一个submit方法里面的参数类型就是Callable。

暂时只需要知道Callable一般是和ExecutorService配合来使用的,具体的使用方法讲在后面讲述。

一般情况下我们使用第一个submit方法和第三个submit方法,第二个submit方法很少使用。

Future

Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果。必要时可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果。

Future类位于java.util.concurrent包下,它是一个接口:

publicinterfaceFuture{

boolean cancel(boolean mayInterruptIfRunning);

boolean isCancelled();

boolean isDone();

V get()throwsInterruptedException,ExecutionException;

V get(long timeout,TimeUnit unit)

throwsInterruptedException,ExecutionException,TimeoutException;}

在Future接口中声明了5个方法,下面依次解释每个方法的作用:

cancel方法用来取消任务,如果取消任务成功则返回true,如果取消任务失败则返回false。参数mayInterruptIfRunning表示是否允许取消正在执行却没有执行完毕的任务,如果设置true,则表示可以取消正在执行过程中的任务。如果任务已经完成,则无论mayInterruptIfRunning为true还是false,此方法肯定返回false,即如果取消已经完成的任务会返回false;如果任务正在执行,若mayInterruptIfRunning设置为true,则返回true,若mayInterruptIfRunning设置为false,则返回false;如果任务还没有执行,则无论mayInterruptIfRunning为true还是false,肯定返回true。isCancelled方法表示任务是否被取消成功,如果在任务正常完成前被取消成功,则返回 true。

isDone方法表示任务是否已经完成,若任务完成,则返回true;

get()方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回;

get(long timeout, TimeUnit unit)用来获取执行结果,如果在指定时间内,还没获取到结果,就直接返回null。

也就是说Future提供了三种功能:

1)判断任务是否完成;

2)能够中断任务;

3)能够获取任务执行结果。

因为Future只是一个接口,所以是无法直接用来创建对象使用的,因此就有了下面的FutureTask。FutureTask

FutureTask实现了RunnableFuture接口,这个接口的定义如下:

publicinterfaceRunnableFutureextendsRunnable,Future{

void run();}

可以看到这个接口实现了Runnable和Future接口,接口中的具体实现由FutureTask来实现。这个类的两个构造方法如下 :

publicFutureTask(Callable callable){

if(callable ==null)

thrownewNullPointerException();

sync =newSync(callable);

}

publicFutureTask(Runnable runnable, V result){

sync =newSync(Executors.callable(runnable, result));

} 如上提供了两个构造函数,一个以Callable为参数,另外一个以Runnable为参数。这些类之间的关联对于任务建模的办法非常灵活,允许你基于FutureTask的Runnable特性(因为它实现了Runnable接口),把任务写成Callable,然后封装进一个由执行者调度并在必要时可以取消的FutureTask。

FutureTask可以由执行者调度,这一点很关键。它对外提供的方法基本上就是Future和Runnable接口的组合:get()、cancel、isDone()、isCancelled()和run(),而run()方法通常都是由执行者调用,我们基本上不需要直接调用它。

一个FutureTask的例子

publicclassMyCallableimplementsCallable{

privatelong waitTime;

publicMyCallable(int timeInMillis){

this.waitTime=timeInMillis;

}

@Override

publicString call()throwsException{ Thread.sleep(waitTime);

//return the thread name executing this callable task

returnThread.currentThread().getName();

}

}

publicclassFutureTaskExample{

publicstaticvoid main(String[] args){

MyCallable callable1 =newMyCallable(1000);// 要执行的任务

MyCallable callable2 =newMyCallable(2000);

FutureTask futureTask1 =newFutureTask(callable1);// 将Callable写的任务封装到一个由执行者调度的FutureTask对象

FutureTask futureTask2 =newFutureTask(callable2);

ExecutorService executor =Executors.newFixedThreadPool(2);// 创建线程池并返回ExecutorService实例

executor.execute(futureTask1);// 执行任务

executor.execute(futureTask2);

while(true){

try{

if(futureTask1.isDone()&& futureTask2.isDone()){// 两个任务都完成System.out.println(“Done”);

executor.shutdown();// 关闭线程池和服务

return;

}

if(!futureTask1.isDone()){// 任务1没有完成,会等待,直到任务完成 System.out.println(“FutureTask1 output=”+futureTask1.get());

}

System.out.println(“Waiting for FutureTask2 to complete”);

String s = futureTask2.get(200L,TimeUnit.MILLISECONDS);

if(s!=null){

System.out.println(“FutureTask2 output=”+s);

}

}catch(InterruptedException|ExecutionException e){

e.printStackTrace();

}catch(TimeoutException e){

//do nothing

}

} }}

运行如上程序后,可以看到一段时间内没有输出,因为get()方法等待任务执行完成然后才输出内容.输出结果如下:

FutureTask1 output=pool-1-thread-1WaitingforFutureTask2 to completeWaitingforFutureTask2 to completeWaitingforFutureTask2 to completeWaitingforFutureTask2 to completeWaitingforFutureTask2 to completeFutureTask2 output=pool-1-thread-2Done

第二篇:Java程序员必须掌握的开发工具

Java程序员必须掌握的开发工具

以下的开发工具,能帮助你成为一名高级java程序开发人员。

1.Eclipse

尽管IntelliJ IDEA、NetBeans和一些其他的IDE正在日益普及,但是有调查表明,Eclipse仍然是几乎半数Java开发人员首选的开发环境。Eclipse是IDE领域的瑞士军刀,有着大量定制的接口和无数的插件。它无处不在,后面本文将推荐的其他所有工具都提供Eclipse插件。这也是八维必讲的开发工具。

Eclipse的工作流程可分为三个方面:工作台,工作空间和视角。工作台作为到IDE的出发点。工作空间将项目、文件和配置设置组合在一个单独的 目录下。视角定义工具、视图和有效设置。虽然新手开发人员可能会觉得相比Netbeans和IntelliJ IDEA,Eclipse使用起来更难,但Eclipse的灵活性,使其成为企业开发的首选IDE。

Luna,Eclipse的最新版本,支持Java

8、分屏编辑、新的黑色主题,以及一个功能齐全的命令行终端。

2.Gradle

Gradle是一个自动化项目工具,建立在Apache Maven和Apache Ant的功能上。虽然Gradle并不是最流行的构建工具(最流行的是Maven,64%的Java开发人员会选择它),但它的普及速度很快。它也可作为默认的Android构建工具。

Gradle引以为傲的是它的简单。Gradle使用Groovy编程语言,与Maven和Ant使用XML语法截然相反。

3.Javadoc

Javadoc是Oracle提供的文档生成器。它可以将特殊格式的注释解析为HTML文档。

Javadoc注释使用开放标签、关闭标签,以及一个或多个描述性标签的格式。开放式标签类似于标准Java多行注释标记,使用两个星号的除外。Javadoc也解析普通的HTML标签。

Javadoc自动格式化标签和关键字,除非另有规定。Javadoc广泛使用超链接,允许你参考和链接到代码的不同区域。许多IDE--包括 Eclipse--可以自动添加Javadoc注释模块到变量、类和方法中。支持Maven、Gradle和Ant的插件在编译代码的同时也可以构建 Javadoc HTML。

4.JUnit

JUnit是用于编写和运行单元测试的开源框架。一个基本的JUnit测试包括测试类、测试方法、以及执行测试的功能。JUnit使用标注来确定测试如何构造和运行。例如,如果你的程序有一个类叫做MathClass,具有乘法和除法的方法,你可以创建JUnit测试来检 查不符合预期的值。输入数字2和5到乘法方法,你希望得到的结果为10。当输入0作为除法方法的第二个参数时,你会期望给出一个数字计算异常的警告因为除 数不能为0:

@Test标注规定,MathClass方法是一个测试用例。在JUnit提供额外的标注,比如@Before,这样你就可以在测试运行之前设置环境。JUnit还可以设置规则用于定义测试方法的行为。例如,TemporaryFolder规则使得一旦测试完成,由测试创建的文件或文件夹就会被删除。

5.Cobertura

Cobertura可用于分析Java代码的测试覆盖率。Cobertura根据没有被测试覆盖的代码生成基于HTML的报告。

Cobertura提供可用于插装、检查和测试代码的工具。通过监控可测试的代码,Cobertura允许你使用你选择的测试框架,甚至不需要测试框架就可以运行程序。

Cobertura根据行、分支和程序包三个方面给出代码覆盖报告。每个类别都有一个可自定义的阈值,如果覆盖面低于阈值,就会触发警告。Cobertura还集成了Maven和Gradle 的自动检测功能。

6.FindBugs

FindBugs是一个匹配编译代码模式,而非使用bug数据库的工具。当提供源代码时,FindBugs还可高亮显示检测出bug的代码行。

在它的3.0.1版本中,FindBugs继续保持着数以百计的bug描述。根据bug的严重程度,FindBugs将bug分为四个水平:相关 的,令人困扰的,可怕的,以及最可怕的。除了图形用户界面,FindBugs还提供一个命令行界面,Ant任务,以及Eclipse插件。

7.VisualVM

包含在JDK中的VisualVM是监控和审查Java应用程序性能的工具。VisualVM检测并重视活跃的JVM实例来检索有关进程的诊断信息。

VisualVM可以很容易地实时诊断性能问题。它提供了全套的分析工具,包括JConsole、jstack、jmap、jinfo和jstat等。此外,你还可以对JVM做一个快照,这样以后在任何时都能审查。

8.Groovy

Groovy是一种编程语言,通过添加新的关键字,自动导入常用的类,以及可选类型变量声明,既简化又扩展了Java。

Groovy的核心优势之一是它的脚本功能。类可以被编译为Java字节码或使用Groovy Shell动态执行。Groovy的Java基础使得它相较于Jython和JRuby更容易为Java开发人员所接受。

第三篇:PHP程序员必须掌握的知识

PHP5的优点

PHP5的最大特点是引入了面向对象的全部机制,并且保留了向下的兼容性。程序员不必再编写缺乏功能性的类,并且能够以多种方法实现类的保护。另外,在对象的集成等方面也不再存在问题。使用PHP5引进了类型提示和异常处理机制,能更有效的处理和避免错误的发生。

mysql_fetch_row,mysql_fetch_array,mysql_fetch_assoc的区别

实例代码

$link=mysql_connect('localhost','root',”);mysql_select_db('abc',$link);$sql = “select * from book”;

$result = mysql_query($sql);

while($row = mysql_fetch_row($result)){

echo $row['cid'].'::'.$row[1].'
';}

$result = mysql_query($sql);

while($row = mysql_fetch_array($result)){

echo $row['cid'].'::'.$row[1].'
';}

$result = mysql_query($sql);

while($row = mysql_fetch_object($result)){

echo $row->cid.'::'.$row->title.”
”;}

$result = mysql_query($sql);

while($row = mysql_fetch_assoc($result)){

echo $row['cid'].'::'.$row[1].'
';}

?>

详细解释:

mysql_fetch_row,这个函数是从结果集中取一行作为枚举数据,从和指定的结果标识关联的结果集中取得一行数据并作为数组返回。每个结果的列 储存在一个数组的单元中,偏移量从 0 开始。注意,这里是从0开始偏移,也就是说不能用字段名字来取值,只能用索引来取值,所以如下代码是取不到值的:

while($row = mysql_fetch_row($res)){

echo $row['cid'].'::'.$row[1].”;

} //这里的$row['cid'] 取不到值。

mysql_fetch_array,从结果集中取得一行作为关联数组,或数字数组,或二者兼有,除了将数据以数字索引方式储存在数组中之外,还可以将数据作为关联索引储存,用字段名作为键名。也就是说他得到的结果像数组一样,可以用key或者索引来取值,所以

while($row = mysql_fetch_array($res)){ echo $row['cid'].'::'.$row[1].”;

}//这里$row['cid'],$row[1]都能得到相应的值。

mysql_fetch_object,顾名思义,从结果集中取得一行作为对象,并将字段名字做为属性。所以只有这样才能取到值

while($row = mysql_fetch_object($res)){ echo $row->cid.'::'.$row->title.”";

}

mysql_fetch_assoc,从结果集中取得一行作为关联数组,也就是说这个函数不能像mysql_fetch_row那样用索引来取值,只能用字段名字来取,所以

while($row = mysql_fetch_assoc($res)){ echo $row['cid'].'::'.$row[1].”;} //$row[1]这样是取不到值的补充一点:

mysql_fetch_array函数是这样定义的:array mysql_fetch_array(resource result [, int result_type]),返回根据从结果集取得的行生成的数组,如果没有更多行则返回 FALSE。

mysql_fetch_array()中可选的第二个参数 result_type 是一个常量,可以接受以下值:MYSQL_ASSOC,MYSQL_NUM 和 MYSQL_BOTH。其中:

1、mysql_fetch_assoc($result)==mysql_fetch_array($result,MYSQL_ASSOC);

2、mysql_fetch_row($result)==mysql_fetch_array($result,MYSQL_NUM);

所 以mysql_fetch_array()函数在某种程度上可以算是mysql_fetch_row()与 mysql_fetch_assoc()的集合。另外,mysql_fetch_array()另外还有MYSQL_BOTH参数,将得到一个同时包含关 联和数字索引的数组。

在来说句 $row = $db->fetch_array($query);

$db是人数据库操作 类,$db->fetch_array($query),fetch_array($query)是那个db类里的方法,$row = $db->fetch_array($query)这句的意思是从记录集$query中得到数据库中的一行记录。

实例代码:

$conn=@mysql_connect($host,$user,$pass);@mysql_select_db($database,$conn);$query=mysql_query($sql);

while($row=mysql_fetch_array($query)){ $rows[]=$row;}

索引(详解)

索引的优点:加快查询速度。

(如果你总结下索引的用途,其实也就这一点了,若是你的面试官说有其他的优点,那你完全可以告诉他,请你回去自己总结下索引这个到底是干什么的吧)

索引类型:

根据数据库的功能,可以在数据库设计器中创建四种索引:唯一索引、非唯一索引、主键索引和聚集索引。尽管唯一索引有助于定位信息,但为获得最佳性能结果,建议改用主键或唯一约束。

唯一索引:

唯一索引是不允许其中任何两行具有相同索引值的索引。

当现有数据中存在重复的键值时,大多数数据库不允许将新创建的唯一索引与表一起保存。数据库还可能防止添加将在表中创建重复键值的新数据。例如,如果在 employee 表中职员的姓(lname)上创建了唯一索引,则任何两个员工都不能同姓。

非唯一索引:

非唯一索引是相对唯一索引,允许其中任何两行具有相同索引值的索引。

当现有数据中存在重复的键值时,数据库是允许将新创建的索引与表一起保存。这时数据库不能防止添加将在表中创建重复键值的新数据。

主键索引:

数据库表经常有一列或列组合,其值唯一标识表中的每一行。该列称为表的主键。

在数据库关系图中为表定义主键将自动创建主键索引,主键索引是唯一索引的特定类型。该索引要求主键中的每个值都唯一。当在查询中使用主键索引时,它还允许对数据的快速访问。

聚集索引(也叫聚簇索引):

在聚集索引中,表中行的物理顺序与键值的逻辑(索引)顺序相同。一个表只能包含一个聚集索引。

如果某索引不是聚集索引,则表中行的物理顺序与键值的逻辑顺序不匹配。与非聚集索引相比,聚集索引通常提供更快的数据访问速度。

第四篇:优秀的java程序员必须掌握的十项技能

西安尚学堂

一个优秀的Java程序员必须掌握的10项技能

3G时代迫使IT从业者中的技术人员掌握越来越多的实用技能,作为IT行业的技术创造者,一个优秀的java程序员必须掌握以下的10项技能,方能胜任java程序员的岗位。

1、语法:必须比较熟悉,在写代码的时候的编辑器对某一行报错应该能够根据报错信息知道是什么样的语法错误并且知道如何修正。

2、命令:必须熟悉自带的常用命令及其常用选项,需要熟悉的命令:appletviewer、Htmlonverter、jar、java、javac、javadoc、javap、javaw、native2ascii、serialver,如果这些命令你没有全部使用过,那么你对java实际上还很不了解。

3、工具:必须至少熟练使用一种IDE的开发工具,例如、Netbeans、JBuilder、Jdeveloper、IDEA、JCreator或者Workshop,包括进行工程管理、常用选项的设置、插件的安装配置以及进行调试。

4、API:的核心API是非常庞大的,但是有一些内容笔者认为是必须熟悉的,否则不可能熟练的运用Java,包括:

◆java.lang包下的80%以上的类的功能的灵活运用。

◆java.util包下的80%以上的类的灵活运用,特别是集合类体系、规则表达式、zip、以及时间、随机数、属性、资源和Timer.◆java.io包下的60%以上的类的使用,理解IO体系的基于管道模型的设计思路以及常用IO类的特性和使用场合。

◆java.math包下的100%的内容。

◆java.net包下的60%以上的内容,对各个类的功能比较熟悉。

◆java.text包下的60%以上的内容,特别是各种格式化类。

◆熟练运用JDBC.8)、java.security包下40%以上的内容,如果对于安全没有接触的话根本就不可能掌握java.◆AWT的基本内容,包括各种组件事件、监听器、布局管理器、常用组件、打印。◆Swing的基本内容,和AWT的要求类似。

◆XML处理,熟悉SAX、DOM以及JDOM的优缺点并且能够使用其中的一种完成XML的解析及内容处理。

5、测试:必须熟悉使用junit编写测试用例完成代码的自动测试。

6、管理:必须熟悉使用ant完成工程管理的常用任务,例如工程编译、生成javadoc、生成jar、版本控制、自动测试。

7、排错:应该可以根据信息比较快速的定位问题的原因和大致位置。

8、思想:必须掌握OOP的主要要求,这样使用Java开发的系统才能是真正的Java系统。

9、规范:编写的代码必须符合流行的编码规范,例如类名首字母大写,成员和方法名首字母小写,方法名的第一个单词一般是动词,包名全部小写等,这样程序的可读性才比较好。

10、博学:掌握、Oracle、WebLogic、Jboss、、Struts、Hibernate 等流行技术,掌握软件架构设计思想、搜索引擎优化、缓存系统设计、网站负载均衡、系统性能调优等实用技术。

第五篇:Java线程总结

Java线程总结

首先要理解线程首先需要了解一些基本的东西,我们现在所使用的大多数操作系统都属于多任务,分时操作系统。正是由于这种操作系统的出现才有了多线程这个概念。我们使用的windows,linux就属于此列。什么是分时操作系统呢,通俗一点与就是可以同一时间执行多个程序的操作系统,在自己的电脑上面,你是不是一边听歌,一边聊天还一边看网页呢?但实际上,并不上cpu在同时执行这些程序,cpu只是将时间切割为时间片,然后将时间片分配给这些程序,获得时间片的程序开始执行,不等执行完毕,下个程序又获得时间片开始执行,这样多个程序轮流执行一段时间,由于现在cpu的高速计算能力,给人的感觉就像是多个程序在同时执行一样。

一般可以在同一时间内执行多个程序的操作系统都有进程的概念.一个进程就是一个执行中的程序,而每一个进程都有自己独立的一块内存空间,一组系统资源.在进程概念中,每一个进程的内部数据和状态都是完全独立的.因此可以想像创建并执行一个进程的系统开像是比较大的,所以线程出现了。在java中,程序通过流控制来执行程序流,程序中单个顺序的流控制称为线程,多线程则指的是在单个程序中可以同时运行多个不同的线程,执行不同的任务.多线程意味着一个程序的多行语句可以看上去几乎在同一时间内同时运行.(你可以将前面一句话的程序换成进程,进程是程序的一次执行过程,是系统运行程序的基本单位)

线程与进程相似,是一段完成某个特定功能的代码,是程序中单个顺序的流控制;但与进程不同的是,同类的多个线程是共享一块内存空间和一组系统资源,而线程本身的数据通常只有微处理器的寄存器数据,以及一个供程序执行时使用的堆栈.所以系统在产生一个线程,或者在各个线程之间切换时,负担要比进程小的多,正因如此,线程也被称为轻负荷进程(light-weight process).一个进程中可以包含多个线程.多任务是指在一个系统中可以同时运行多个程序,即有多个独立运行的任务,每个任务对应一个进程,同进程一样,一个线程也有从创建,运行到消亡的过程,称为线程的生命周期.用线程的状态(state)表明线程处在生命周期的哪个阶段.线程有创建,可运行,运行中,阻塞,死亡五中状态.通过线程的控制与调度可使线程在这几种状态间转化每个程序至少自动拥有一个线程,称为主线程.当程序加载到内存时,启动主线程.[线程的运行机制以及调度模型]

java中多线程就是一个类或一个程序执行或管理多个线程执行任务的能力,每个线程可以独立于其他线程而独立运行,当然也可以和其他线程协同运行,一个类控制着它的所有线程,可以决定哪个线程得到优先级,哪个线程可以访问其他类的资源,哪个线程开始执行,哪个保持休眠状态。下面是线程的机制图:

Page 1 of 16

线程的状态表示线程正在进行的活动以及在此时间段内所能完成的任务.线程有创建,可运行,运行中,阻塞,死亡五中状态.一个具有生命的线程,总是处于这五种状态之一: 1.创建状态

使用new运算符创建一个线程后,该线程仅仅是一个空对象,系统没有分配资源,称该线程处于创建状态(new thread)2.可运行状态

使用start()方法启动一个线程后,系统为该线程分配了除CPU外的所需资源,使该线程处于可运行状态(Runnable)3.运行中状态

Java运行系统通过调度选中一个Runnable的线程,使其占有CPU并转为运行中状态(Running).此时,系统真正执行线程的run()方法.4.阻塞状态

一个正在运行的线程因某种原因不能继续运行时,进入阻塞状态(Blocked)5.死亡状态

线程结束后是死亡状态(Dead)

同一时刻如果有多个线程处于可运行状态,则他们需要排队等待CPU资源.此时每个线程自动获得一个线程的优先级(priority),优先级的高低反映线程的重要或紧急程度.可运行状态的线程按优先级排队,线程调度依据优先级基础上的“先到先服务”原则.线程调度管理器负责线程排队和CPU在线程间的分配,并由线程调度算法进行调度.当线程调度管理器选种某个线程时,该线程获得CPU资源而进入运行状态.线程调度是先占式调度,即如果在当前线程执行过程中一个更高优先级的线程进入可运行状态,则这个线程立即被调度执行.先占式调度分为:独占式和分时方式.独占方式下,当前执行线程将一直执行下去,直 到执行完毕或由于某种原因主动放弃CPU,或CPU被一个更高优先级的线程抢占

分时方式下,当前运行线程获得一个时间片,时间到时,即使没有执行完也要让出

Page 2 of 16

CPU,进入可运行状态,等待下一个时间片的调度.系统选中其他可运行状态的线程执行

分时方式的系统使每个线程工作若干步,实现多线程同时运行

另外请注意下面的线程调度规则(如果有不理解,不急,往下看): ①如果两个或是两个以上的线程都修改一个对象,那么把执行修改的方法定义为被同步的(Synchronized),如果对象更新影响到只读方法,那么只度方法也应该定义为同步的

②如果一个线程必须等待一个对象状态发生变化,那么它应该在对象内部等待,而不是在外部等待,它可以调用一个被同步的方法,并让这个方法调用wait()③每当一个方法改变某个对象的状态的时候,它应该调用notifyAll()方法,这给等待队列的线程提供机会来看一看执行环境是否已发生改变

④记住wait(),notify(),notifyAll()方法属于Object类,而不是Thread类,仔细检查看是否每次执行wait()方法都有相应的notify()或notifyAll()方法,且它们作用与相同的对象 在java中每个类都有一个主线程,要执行一个程序,那么这个类当中一定要有main方法,这个man方法也就是java class中的主线程。你可以自己创建线程,有两种方法,一是继承Thread类,或是实现Runnable接口。一般情况下,最好避免继承,因为java中是单根继承,如果你选用继承,那么你的类就失去了弹性,当然也不能全然否定继承Thread,该方法编写简单,可以直接操作线程,适用于单重继承情况。至于选用那一种,具体情况具体分析。

eg.继承Thread

public class MyThread_1 extends Thread{ public void run(){ //some code } }

eg.实现Runnable接口

public class MyThread_2 implements Runnable { public void run(){ //some code } }

Page 3 of 16

当使用继承创建线程,这样启动线程:

new MyThread_1().start()

当使用实现接口创建线程,这样启动线程:

new Thread(new MyThread_2()).start()

注意,其实是创建一个线程实例,并以实现了Runnable接口的类为参数传入这个实例,当执行这个线程的时候,MyThread_2中run里面的代码将被执行。下面是完成的例子:

public class MyThread implements Runnable { public void run(){ System.out.println(“My Name is ”+Thread.currentThread().getName());} public static void main(String[] args){ new Thread(new MyThread()).start();} }

执行后将打印出: My Name is Thread-0

你也可以创建多个线程,像下面这样

new Thread(new MyThread()).start();new Thread(new MyThread()).start();new Thread(new MyThread()).start();

那么会打印出:

My Name is Thread-0 My Name is Thread-1

Page 4 of 16

My Name is Thread-2

看了上面的结果,你可能会认为线程的执行顺序是依次执行的,但是那只是一般情况,千万不要用以为是线程的执行机制;影响线程执行顺序的因素有几点:首先看看前面提到的优先级别

public class MyThread implements Runnable { public void run(){ System.out.println(“My Name is ”+Thread.currentThread().getName());} public static void main(String[] args){ Thread t1=new Thread(new MyThread());Thread t2=new Thread(new MyThread());Thread t3=new Thread(new MyThread());

t2.setPriority(Thread.MAX_PRIORITY);//赋予最高优先级

t1.start();t2.start();t3.start();} }

再看看结果:

My Name is Thread-1 My Name is Thread-0 My Name is Thread-2

Page 5 of 16

线程的优先级分为10级,分别用1到10的整数代表,默认情况是5。上面的t2.setPriority(Thread.MAX_PRIORITY)等价与t2.setPriority(10)

然后是线程程序本身的设计,比如使用sleep,yield,join,wait等方法(详情请看JDKDocument)

public class MyThread implements Runnable { public void run(){

try {

int sleepTime =(int)(Math.random()* 100);// 产生随机数字,Thread.currentThread().sleep(sleepTime);// 让其休眠一定时间,时间又上面sleepTime决定

// public static void sleep(long millis)throw InterruptedException

//(API)

System.out.println(Thread.currentThread().getName()+ “ 睡了 ”

+ sleepTime);

} catch(InterruptedException ie)

// 由于线程在休眠可能被中断,所以调用sleep方法的时候需要捕捉异常

Page 6 of 16

{

ie.printStackTrace();

} }

public static void main(String[] args){

Thread t1 = new Thread(new MyThread());

Thread t2 = new Thread(new MyThread());

Thread t3 = new Thread(new MyThread());

t1.start();

t2.start();

t3.start();} }

执行后观察其输出: Thread-0 睡了 11 Thread-2 睡了 48 Thread-1 睡了 69

上面的执行结果是随机的,再执行很可能出现不同的结果。由于上面我在run中添加了休眠语句,当线程休眠的时候就会让出cpu,cpu将会选择执行处于runnable状态中的其他线程,当然也可能出现这种情况,休眠的Thread立即进入了runnable状态,cpu再次执行它。[线程组概念] 线程是可以被组织的,java中存在线程组的概念,每个线程都是一个线程组的成员,线程组把多个线程集成为一个对象,通过线程组可以同时对其中的多个线程进行操作,如启动一个线程组的所有线程等.Java的线程组由java.lang包中的Thread——Group类实现.ThreadGroup类用来管理一组线程,包括:线程的数目,线程间的关系,线程正在执行的操作,以及线程将要启动或终止时间等.线程组还可以包含线程组.在Java的应用程序中,最高层的线程组是名位main的线程组,在main中还可以加入线程或

Page 7 of 16

线程组,在mian的子线程组中也可以加入线程和线程组,形成线程组和线程之间的树状继承关系。像上面创建的线程都是属于main这个线程组的。借用上面的例子,main里面可以这样写:

public static void main(String[] args){

/***************************************

* ThreadGroup(String name)ThreadGroup(ThreadGroup parent, String name)

***********************************/

ThreadGroup group1 = new ThreadGroup(“group1”);

ThreadGroup group2 = new ThreadGroup(group1, “group2”);

Thread t1 = new Thread(group2, new MyThread());

Thread t2 = new Thread(group2, new MyThread());

Thread t3 = new Thread(group2, new MyThread());

t1.start();

t2.start();

t3.start();} 线程组的嵌套,t1,t2,t3被加入group2,group2加入group1。

Page 8 of 16

另外一个比较多就是关于线程同步方面的,试想这样一种情况,你有一笔存款在银行,你在一家银行为你的账户存款,而你的妻子在另一家银行从这个账户提款,现在你有1000块在你的账户里面。你存入了1000,但是由于另一方也在对这笔存款进行操作,人家开始执行的时候只看到账户里面原来的1000元,当你的妻子提款1000元后,你妻子所在的银行就认为你的账户里面没有钱了,而你所在的银行却认为你还有2000元。看看下面的例子:

class BlankSaving // 储蓄账户 { private static int money = 10000;

public void add(int i){

money = money + i;

System.out.println(“Husband 向银行存入了 [¥” + i + “]”);}

public void get(int i){

money = money-i;

System.out.println(“Wife 向银行取走了 [¥” + i + “]”);

if(money < 0)

System.out.println(“余额不足!”);}

Page 9 of 16

public int showMoney(){

return money;} }

class Operater implements Runnable { String name;BlankSaving bs;

public Operater(BlankSaving b, String s){

name = s;

bs = b;

}

public static void oper(String name, BlankSaving bs){

if(name.equals(“husband”)){

try {

for(int i = 0;i < 10;i++){

Page 10 of 16

Thread.currentThread().sleep((int)(Math.random()* 300));

bs.add(1000);

}

} catch(InterruptedException e){

}

} else {

try {

for(int i = 0;i < 10;i++){

Thread.currentThread().sleep((int)(Math.random()* 300));

bs.get(1000);

}

} catch(InterruptedException e){

}

} }

public void run(){

oper(name, bs);}

Page 11 of 16

}

public class BankTest { public static void main(String[] args)throws InterruptedException {

BlankSaving bs = new BlankSaving();

Operater o1 = new Operater(bs, “husband”);

Operater o2 = new Operater(bs, “wife”);

Thread t1 = new Thread(o1);

Thread t2 = new Thread(o2);

t1.start();

t2.start();

Thread.currentThread().sleep(500);} }

下面是其中一次的执行结果:

---------first--------------Husband 向银行存入了 [¥1000] Wife 向银行取走了 [¥1000] Wife 向银行取走了 [¥1000] Husband 向银行存入了 [¥1000] Wife 向银行取走了 [¥1000] Husband 向银行存入了 [¥1000] Wife 向银行取走了 [¥1000] Husband 向银行存入了 [¥1000] Wife 向银行取走了 [¥1000] Husband 向银行存入了 [¥1000] Husband 向银行存入了 [¥1000]

Page 12 of 16

Wife 向银行取走了 [¥1000] Husband 向银行存入了 [¥1000] Husband 向银行存入了 [¥1000] Wife 向银行取走了 [¥1000] Wife 向银行取走了 [¥1000] Husband 向银行存入了 [¥1000] Wife 向银行取走了 [¥1000] Wife 向银行取走了 [¥1000] Husband 向银行存入了 [¥1000]

看到了吗,这可不是正确的需求,在husband还没有结束操作的时候,wife就插了进来,这样很可能导致意外的结果。解决办法很简单,就是将对数据进行操作方法声明为synchronized,当方法被该关键字声明后,也就意味着,如果这个数据被加锁,只有一个对象得到这个数据的锁的时候该对象才能对这个数据进行操作。也就是当你存款的时候,这笔账户在其他地方是不能进行操作的,只有你存款完毕,银行管理人员将账户解锁,其他人才能对这个账户进行操作。

修改public static void oper(String name,BlankSaving bs)为public static void oper(String name,BlankSaving bs),再看看结果:

Husband 向银行存入了 [¥1000] Husband 向银行存入了 [¥1000] Husband 向银行存入了 [¥1000] Husband 向银行存入了 [¥1000] Husband 向银行存入了 [¥1000] Husband 向银行存入了 [¥1000] Husband 向银行存入了 [¥1000] Husband 向银行存入了 [¥1000] Husband 向银行存入了 [¥1000] Husband 向银行存入了 [¥1000] Wife 向银行取走了 [¥1000] Wife 向银行取走了 [¥1000] Wife 向银行取走了 [¥1000] Wife 向银行取走了 [¥1000] Wife 向银行取走了 [¥1000] Wife 向银行取走了 [¥1000] Wife 向银行取走了 [¥1000] Wife 向银行取走了 [¥1000] Wife 向银行取走了 [¥1000] Wife 向银行取走了 [¥1000]

当丈夫完成操作后,妻子才开始执行操作,这样的话,对共享对象的操作就不会有问题了。

[wait and notify] 你可以利用这两个方法很好的控制线程的执行流程,当线程调用wait方法后,线

Page 13 of 16

程将被挂起,直到被另一线程唤醒(notify)或则是如果wait方法指定有时间得话,在没有被唤醒的情况下,指定时间时间过后也将自动被唤醒。但是要注意一定,被唤醒并不是指马上执行,而是从组塞状态变为可运行状态,其是否运行还要看cpu的调度。事例代码:

class MyThread_1 extends Thread {

Object lock;

public MyThread_1(Object o){

lock = o;}

public void run(){

try {

synchronized(lock){

System.out.println(“Enter Thread_1 and wait”);

lock.wait();

System.out.println(“be notified”);

}

} catch(InterruptedException e){

} }

Page 14 of 16

}

class MyThread_2 extends Thread { Object lock;

public MyThread_2(Object o){

lock = o;}

public void run(){

synchronized(lock){

System.out.println(“Enter Thread_2 and notify”);

lock.notify();

} } }

public class MyThread { public static void main(String[] args){

int[] in = new int[0];// notice

MyThread_1 t1 = new MyThread_1(in);

Page 15 of 16

MyThread_2 t2 = new MyThread_2(in);

t1.start();

t2.start();} }

执行结果如下:

Enter Thread_1 and wait Enter Thread_2 and notify Thread_1 be notified

可能你注意到了在使用wait and notify方法得时候我使用了synchronized块来包装这两个方法,这是由于调用这两个方法的时候线程必须获得锁,也就是上面代码中的lock[],如果你不用synchronized包装这两个方法的得话,又或则锁不一是同一把,比如在MyThread_2中synchronized(lock)改为synchronized(this),那么执行这个程序的时候将会抛出java.lang.IllegalMonitorStateException执行期异常。另外wait and notify方法是Object中的,并不在Thread这个类中。最后你可能注意到了这点:int[] in=new int[0];为什么不是创建new Object而是一个0长度的数组,那是因为在java中创建一个0长度的数组来充当锁更加高效。

Page 16 of 16

下载Java程序员必须掌握的线程知识(精选五篇)word格式文档
下载Java程序员必须掌握的线程知识(精选五篇).doc
将本文档下载到自己电脑,方便修改和收藏,请勿使用迅雷等下载。
点此处下载文档

文档为doc格式


声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:645879355@qq.com 进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。

相关范文推荐

    java工程师学习必须掌握的的知识

    第一学期课程学习完成之后,成为一名熟练操作数据库并可以基于数据的Java应用程序的高级程序员,Java的软件工程师、JSP web 开发工程师,可承担java高级程序设计及电子商务开发......

    java程序员需要掌握些什么知识握些什么知

    java程序员需要掌握些什么知识合格的程序员应具有实际开发能力的Java和J2EE。如今的IT企业需求量大,但人才紧缺的。企业需要大量掌握Java/JEE/Oracle/WebLogic/Websphere, S......

    java程序员应该掌握的Linux系统的知识

    大型J2EE应用都在建构在linux环境下的。开发环境下我们可以通过samba映射成本地的网络驱动器,直接在windows环境下进行编程调试。但是最后的发布还是要到linux环境,同时我们对......

    Java线程编程总结

    线程编程方面60、java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用? 答:有两种实现方法,分别是继承Thread类与实现Runnable接......

    java程序员需掌握的知识点

    一、数据库事务 答:是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。事务处理可以确保事务性单元内的所有操作都成功完成,否则永久不会更新面向数......

    消防安全知识(必须掌握)

    消防安全知识 (全员培训、全员熟记、达到“一口清、问不倒”) 一、怎样报火警? 答:1、拨打火警电话119,并确认; 2、不要慌张,讲明起火单位名称,所在位置,起火物质是什么,有无人员被困,......

    程序员需要掌握的知识

    程序员需要掌握的知识 2011年11月3日 1:01 补充: (1)掌握一种方法学或者说思想,现在基本都是面向对象(OOA/OOD设计模式) (2)项目管理、体系结构、架构知识 (3)多参考经典代码 (4)加强英......

    熟练的Java程序员应该掌握哪些技术?

    熟练的Java程序员应该掌握哪些技术?Java程序员应该掌握哪些技术才能算是脱离菜鸟达到熟练的程度? 1、语法:Java程序员必须比较熟悉语法,在写代码的时候IDE的编辑器对某一行报错......