疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

详细如何管理多线程


 

   

  详细的介绍如何管理多线程,包括:对线程的等待、守护线程、线程的睡眠、线程的突然停止、线程的让步、线程的优先级等。由于内容比较多,本节先介绍前两部分:对线程的等待、守护线程

  1、线程的等待

  我们常常对同一件事情进行切割,分成多干件小的事情后,再开辟多条线程来处理(有点分治的味道)。在多件事情处理完成之后我们需要再统一的处理。这样说有点枯燥:比如我们要导出一份文件,这个文件的行数非常多大概几十万行数据。直接导出也可以,会导致系统卡一下,严重一点的可能会超时。这时候怎么办呢?我们可以分成若干份,比如每五千条数据是一份数据,然后用一条线程去导出到文件中,这样就会生成若干份文件。当所有的文件都导出后,我们把这些数据汇总一下就OK了。但是这里有一个问题,什么时候所有线程都导完数据了呢?我们总不能一个一个的去检查文件是否存在吧。

  这里java为我们提供了一个专门用于等待的方法Join().当某条线程执行了其他线程的join()方法以后,当前线程就会阻塞,直到其他线程执行结束以后,才可以运行。

  如下述代码:

  1 public class newThread extends Thread

  2 {

  3 public newThread(String name)

  4 {

  5 super(name);

  6 }

  7 public void run()

  8 {

  9 int i=100;

  10 while(i-->0)

  11 {

  12 sleep(100);

  13 }

  14 }

  15

  16 public static void main(String args)throws Exception

  17 {

  18 Thread son_1=new newThread("thread-1");

  19 Thread son_2=new newThread("thread-2");

  20 son_1.start();

  21 son_2.start();

  22 son_1.join();//注意这里

  23 son_2.join();

  24 System.out.println("all threads is over")

  25 }

  26 }

  我们分别启动thread 1 和thread 2。这两条线程会分别运行,互相不影响,然后我们用主线程来等待线程1,直到它结束,我们才开始等待线程2。如果线程1比线程2的用时长的话,再我们等待完线程1 后,线程2将无需等待,直接输出结果。

  join方法共有三种形式的重载

  1 join()

  2 join(long millis)//

  3 join(long millis,int nanos)//millis 毫秒 nanos微秒

  第一个方法时直到等待线程结束才继续向下运行,第二和第三个方法则是在限定时间内等待,如果时间结束将不会继续等待(可以用于超时判断),注意第三个方法并不常用,这里主要是因为java和硬件对时间的把控根本难以精确到微秒级,所以并不能很准确到控制。

  2、守护线程

  守护线程(Daemon Thread)又叫做精灵线程、后台线程。乍一听守护二字,觉得好像很厉害的意思,像是在保护其他线程的线程,其实很简单,并没有那么玄。所有的语言设计,都是为了更方便的使用。

  设想这样一个场景:在一个考场内,考生们都在埋头答卷,除了考生,还有监考老师,他的职责就是为了维护考场的秩序,对于有困难的考生提供帮助。当所有的考生都交卷后(或者时间到了以后,考生被强制交卷(结束线程)),这个监考老师的义务已经完成,无需继续运行。简而言之,这个监考老师是为了其他学生提供后台服务的,当所有的考生都已经停笔后,老师的义务也已经结束了,可以退场了。

  有些人看到这里,可能会觉得,这还不简单,我们只要如线程等待让老师等待所有的学生都结束之后,不就可以了么?!这个回答对也不对。对的是老师的线程的确是在等待学生线程结束,不对的地方是老师线程在等待的同时,还在提供服务,并不是所有学生停笔后收卷这么简单。在Jvm中有一个所有开发者都熟悉的线程GC,它就是在其他线程运行的同时,默默的提供服务,当其他线程结束后,他又默默的退场。

  如下代码

  复制代码

  1 public class newThread extends Thread

  2 {

  3 public newThread(String name)

  4 {

  5 super(name);

  6 }

  7 public void run()

  8 {

  9 int i=100;

  10 while(i-->0)

  11 {

  12 sleep(100);

  13 }

  14 }

  15

  16 public static void main(String args)throws Exception

  17 {

  18 Thread son_1=new newThread("thread-1");

  19 Thread son_2=new newThread("thread-2");

  20 Thread daemonThread=new newThread("thread-daemonThread");

  21 son_1.start();

  22 son_2.start();

  23

  24 daemonThread.setDaemon(true);//注意看这里

  25 daemonThread.start();

  26 son_1.join();

  27 son_2.join();

  28 System.out.println("all son_threads is over")

  29 }

  30 }

  31

  32 class DaemonThread

  33 {

  34 public DaemonThread(String name)

  35 {

  36 super(name);

  37 }

  38 public void run()

  39 {

  40 int i=1000;

  41 while(i-->0)

  42 {

  43 sleep(100);

  44 }

  45 }

  46 }

  复制代码

  在代码中 Daemonthread线程被设置为后台线程,则当主线程等待子线程结束后, Daemonthread线程也会结束,不会继续运行。我们可以用这种方式设置一种线程,专门用来维护其他线程的正常运行,比如后台计数,计时,查询各个客户端是否保持在线(心跳),推送事件等。

  java还专门提供了 IsDaemon()的方法来判断这个线程是否为后台线程。这里有一点注意的是,如果要设置一个线程为后台线程,必须要在这个线程还没有开始“就绪”(start())时设置,否则会引发非法的线程状态异常