Java多线程——多线程方法详解 Java多线程——多线程方法详解

摘自:https://www.cnblogs.com/wgblog-code/p/11928825.html

Java多线程——多线程方法详解

 

本系列文章是Java多线程的详解介绍,对多线程还不熟悉的同学可以先去看一下我的这篇博客Java基础系列3:多线程超详细总结,这篇博客从宏观层面介绍了多线程的整体概况,接下来的几篇文章是对多线程的深入剖析。

多线程的常用方法

1、currentThread()方法:

介绍:currentThread()方法可返回该代码正在被哪个线程调用的信息。

示例

例1:

1
2
3
4
5
6
7
8
9
10
public  class  Test01 {
 
     public  static  void  main(String[] args) {
         System.out.println(Thread.currentThread().getName());
     }
     
}
 
结果:
main

  

结果说明,main方法被名为main的线程调用

例2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class  Mythread  extends  Thread{
     
     public  Mythread() {
         System.out.println( "构造方法的打印:" +Thread.currentThread().getName());
     }
     
     @Override
     public  void  run() {
         System.out.println( "run方法的打印:" +Thread.currentThread().getName());
     }
}
 
public  class  Test01 {
 
     public  static  void  main(String[] args) {
         Mythread t= new  Mythread();
         t.start(); //①
     }
     
}
 
结果:
构造方法的打印:main
run方法的打印:Thread- 0

  

从结果可知:Mythread的构造方法是被main线程调用的,而run方法是被名称为Thread-0的线程调用的,run方法是线程自动调用的

现在我们将①处的代码改为t.run(),现在的输出结果如下:

1
2
构造方法的打印:main
run方法的打印:main

  

从结果中我们可以看到两次的结果显示都是main线程调用了方法,因为当你使用t.start()方法的时候是线程自动调用的run()方法,所以输出的是Thread-0,当你直接调用run()方法时,和调用普通方法没有什么区别,所以是main线程调用run()

2、isAlive()方法:

介绍:isAlive()方法的功能是判断当前的线程是否处于活动状态

示例:

例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class  Mythread  extends  Thread{
     
     @Override
     public  void  run() {
         System.out.println( "run ==" + this .isAlive());
     }
     
}
 
public  class  Test01 {
 
     public  static  void  main(String[] args) {
         Mythread thread= new  Mythread();
         System.out.println( "begin ==" +thread.isAlive()); //①
         thread.start(); //②
         System.out.println( "end ==" +thread.isAlive()); //③
     }
     
}
 
结果:
begin == false
end == true
run == true

  

方法isAlive()的作用是测试线程是否处于活动状态。那么什么情况下是活动状态呢?活动状态就是线程已经启动且尚未停止。线程处于正在运行或准备开始运行的状态,就认为线程是存活的

①处代码的结果为false,因为此时线程还未启动;

②处代码调用了run()方法输出结果为run ==true,此时线程处于活动状态;

③处代码的结果为true,有的同学看到这个输出可能会不理解,不是说线程处于活动状态isAlive()方法的结果才是true,现在程序都已经运行结束了为什么还是true?这里的输出结果是不确定的,我们再来看下面一段代码

我们将例1中的代码稍做修改,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public  class  Test01 {
 
     public  static  void  main(String[] args)  throws  InterruptedException {
         Mythread thread= new  Mythread();
         System.out.println( "begin ==" +thread.isAlive()); //①
         thread.start(); //②
         Thread.sleep( 1000 ); //这里加了一行代码,让当前线程沉睡1秒
         System.out.println( "end ==" +thread.isAlive()); //③
     }
     
}
 
结果:
begin == false
run == true
end == false

  

现在我们看到③处的代码结果为end ==false,因为thread对象已经在1秒内执行完毕,而上面代码输出结果为true是因为thread线程未执行完毕。

3、sleep()方法:

介绍:

方法sleep()的作用是在指定的毫秒数内让当前“正在执行的线程”休眠(暂停执行),这个“正在执行的线程”是指this.currentThread()返回的线程。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class  Mythread  extends  Thread{
     
     @Override
     public  void  run() {
         
         try  {
             System.out.println( "run threadName=" + this .currentThread().getName()+ " begin" );
             Thread.sleep( 2000 );
             System.out.println( "run threadName=" + this .currentThread().getName()+ " end" );
             
         catch  (InterruptedException e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
         }
         
     }
     
}
 
public  class  Test01 {
 
     public  static  void  main(String[] args)  throws  InterruptedException {
         Mythread thread= new  Mythread();
         System.out.println( "begin =" +System.currentTimeMillis());
         thread.run(); //①
         System.out.println( "end =" +System.currentTimeMillis());
     }
     
}
 
结果:
begin = 1574660731663
run threadName=main begin
run threadName=main end
end = 1574660733665

  

从结果中可以看出main线程暂停了2秒(因为这里调用的是thread.run())

下面我们将①处的代码改成thread.start(),再来看下运行结果:

1
2
3
4
begin = 1574661491412
end = 1574661491412
run threadName=Thread- 0  begin
run threadName=Thread- 0  end

  

由于main线程与thread线程是异步执行的,所以首先打印的信息为begin和end,而thread线程是随后运行的,在最后两行打印run begin和run end的信息。

4、getId()方法:

介绍:getId()方法的作用是取得线程的唯一标识

示例

1
2
3
4
5
6
7
8
public  class  Test01 {
 
     public  static  void  main(String[] args)  throws  InterruptedException {
         Thread thread=Thread.currentThread();
         System.out.println(thread.getName()+ " " +thread.getId());
     }
     
}<br><br>结果:main  1

  

从运行结果可以看出,当前执行代码的线程名称是main,线程id值为1

5、停止线程:

介绍:停止线程是在多线程开发时很重要的技术点,掌握此技术可以对线程的停止进行有效的处理。停止线程在Java语言中并不像break语句那样干脆,需要一些技巧性的处理。

在java中有三种方法可以停止线程

  1. 使用退出标志,让线程正常退出,也就是当run方法执行完之后终止
  2. 使用stop方法强制终止线程,但是不推荐使用,因为stop和suspend及resume一样,是java废弃的方法
  3. 使用interrupt方法中断线程(推荐使用)

示例:

例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class  Mythread  extends  Thread{
     
     @Override
     public  void  run() {
         
         for ( int  i= 0 ;i< 5000 ;i++) {
             System.out.println( "i=" +(i+ 1 ));
         }
     }
     
}
 
public  class  Test01 {
 
     public  static  void  main(String[] args)  throws  InterruptedException {
         Mythread thread= new  Mythread();
         thread.start();
         Thread.sleep( 2000 );
         thread.interrupt();
     }
     
}

  

运行结果:

从运行结果我们可以看出最后i=500000,调用interrupt方法没有停止线程,那么该如何停止线程呢?

在介绍如何停止线程时,我们先来介绍一下如何判断线程是否处于停止状态

Thread类中提供了两种方法用来判断线程是否停止:

1、this.interrupted():测试当前线程是否已经中断,执行后具有将状态标志清除为false的功能

1
2
3
public  static  boolean  interrupted() {
         return  currentThread().isInterrupted( true );
}

  

2、this.isInterrupted():测试线程Thread对象是否已经中断,但是不清除状态标志

1
2
3
public  boolean  isInterrupted() {
         return  isInterrupted( false );
}

  

读者可以仔细观看一下这两个方法的声明有什么不同?

例2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class  Mythread  extends  Thread{
     
     @Override
     public  void  run() {
         
         for ( int  i= 0 ;i< 5000 ;i++) {
             System.out.println( "i=" +(i+ 1 ));
         }
     }
     
}
 
public  class  Test01 {
 
     public  static  void  main(String[] args)  throws  InterruptedException {
         Mythread thread= new  Mythread();
         thread.start();
         Thread.sleep( 1000 );
         thread.interrupt();
         System.out.println( "是否停止1?=" +thread.interrupted());
         System.out.println( "是否停止2?=" +thread.interrupted());
         System.out.println( "end!" );
     }
     
}

  

结果:

 输出结果显示调用了thread.interrupt()方法后线程并未停止,这也就证明了interrupted()方法的解释:测试当前线程是否已经中断。这个当前线程是main,它从未断过,所以打印的结果是两个false。

如果想让main线程结束该怎么做?

将main方法改成如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public  class  Test01 {
 
     public  static  void  main(String[] args)  throws  InterruptedException {
         Thread.currentThread().interrupt();
         System.out.println( "是否停止1?=" +Thread.interrupted());
         System.out.println( "是否停止2?=" +Thread.interrupted());
         System.out.println( "end!" );
     }
     
}
 
结果:
是否停止 1 ?= true
是否停止 2 ?= false
end!

  

从输出结果我们可以看出,方法interrupted()的确判断出当前线程是否是停止状态。但为什么第2个值是false?

查看一下官方文档的介绍:

测试当前线程是否已经中断。线程的中断状态由该方法清除。换句话说,如果连续两次调用该方法,则第二次调用将返回false(在第一次调用已清除了其中断状态之后,且第二次调用检验完中断状态前,当前线程再次中断的情况除外)。

 文档中说明的非常清楚,interrupted()方法具有清除状态的功能,所以第二次调用interrupted方法返回的值时false。

下面我们来看一下isInterrupted()方法,将main方法改成如下代码:

1
2
3
4
5
6
7
8
9
public  static  void  main(String[] args)  throws  InterruptedException {
         Mythread thread= new  Mythread();
         thread.start();
         thread.interrupt();
         Thread.sleep( 1000 );
         System.out.println( "是否停止1?=" +thread.isInterrupted());
         System.out.println( "是否停止2?=" +thread.isInterrupted());
         System.out.println( "end" );
}<br>结果:<br><br>是否停止 1 ?= true <br>是否停止 2 ?= true <br>end

  

从结果可以看出,方法isInterrrupted()并未清除状态,所以结果为两个true。

例3:在沉睡中停止

当线程调用sleep()方法后再调用interrupt()方法后会有什么结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class  Mythread  extends  Thread{
     
     @Override
     public  void  run() {
         
         try  {
             System.out.println( "run begin" );
             Thread.sleep( 200000 );
             System.out.println( "run end" );
         catch  (InterruptedException e) {
             System.out.println( "在沉睡中被停止,进入catch!" + this .isInterrupted());
             e.printStackTrace();
         }
     }
     
}
 
public  class  Test01 {
 
     public  static  void  main(String[] args)  throws  InterruptedException {
         try  {
             Mythread thread= new  Mythread();
             thread.start();
             Thread.sleep( 200 );
             thread.interrupt();
         } catch (Exception e) {
             System.out.println( "main catch" );
             e.printStackTrace();
         }
         System.out.println( "end!" );
     }
     
}

  

6、暂停线程:

暂停线程意味着此线程还可以恢复运行。在java多线程中,可以使用suspend()方法暂停线程,使用resume()方法恢复线程的执行

例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class  Mythread  extends  Thread{
     
     private  long  i= 0 ;
     public  long  getI() {
         return  i;
     }
     
     public  void  setI( long  i) {
         this .i = i;
     }
     
     @Override
     public  void  run() {
         while ( true ) {
             i++;
         }
     }
     
}
 
public  class  Test01 {
 
     public  static  void  main(String[] args)  throws  InterruptedException {
         
         Mythread thread= new  Mythread();
         thread.start();
         Thread.sleep( 5000 );
         //A段
         thread.suspend();
         System.out.println( "A= " +System.currentTimeMillis()+ " i=" +thread.getI());
         Thread.sleep( 5000 );
         System.out.println( "A= " +System.currentTimeMillis()+ " i=" +thread.getI());
         
         //B段
         thread.resume();
         Thread.sleep( 5000 );
         
         //C段
         thread.suspend();
         System.out.println( "B= " +System.currentTimeMillis()+ " i=" +thread.getI());
         Thread.sleep( 5000 );
         System.out.println( "B= " +System.currentTimeMillis()+ " i=" +thread.getI());
         
     }
     
}

  

结果:


从控制台打印的时间上来看,线程的确被暂停了,而且还可以恢复成运行状态。

7、yield方法:

介绍:yield()方法的作用是放弃当前的CPU资源,将它让给其他的任务去占用CPU执行时间。但放弃的时间不确定,有可能刚刚放弃,马上又获得CPU时间片

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class  Mythread  extends  Thread{
     
     @Override
     public  void  run() {
         long  beginTime=System.currentTimeMillis();
         int  count= 0 ;
         for ( int  i= 0 ;i< 500000 ;i++) {<br>                //Thread.yield();①
             count=count+(i+ 1 );
         }
         long  endTime=System.currentTimeMillis();
         System.out.println( "用时:" +(endTime-beginTime)+ "毫秒!" );
     }
     
}
 
public  class  Test01 {
 
     public  static  void  main(String[] args)  throws  InterruptedException {
         Mythread thread= new  Mythread();
         thread.start();
     }
     
}<br><br>结果:用时: 2 毫秒!

  

现在将①处的代码取消注释,我们再来看一下运行结果:

1
用时: 213 毫秒!

  

将CPU让给其他资源导致速度变慢

8、线程优先级:

介绍:

在操作系统中,线程可以划分优先级,优先级较高的线程得到的CPU资源较多,也就是CPU优先执行优先级较高的线程对象中的任务。

设置线程优先级有助于帮“线程规划器”确定在下一次选择哪一个线程来优先执行。

设置线程的优先级使用setPriority()方法,此方法在JDK的源代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
public  final  void  setPriority( int  newPriority) {
         ThreadGroup g;
         checkAccess();
         if  (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
             throw  new  IllegalArgumentException();
         }
         if ((g = getThreadGroup()) !=  null ) {
             if  (newPriority > g.getMaxPriority()) {
                 newPriority = g.getMaxPriority();
             }
             setPriority0(priority = newPriority);
         }
}

  

在Java中,线程的优先级为1-10这10个等级,如果小于1或大于10,则JDK抛出异常throw new IllegalArgumentException()。

通常高优先级的线程总是先执行完,但是并不是一定的,高优先级和低优先级的线程会交替进行,高优先级执行的次数多一些

线程优先级的继承特性:

在Java中,线程的优先级具有继承性,比如A线程启动B线程,则B线程的优先级与A是一样的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class  Mythread2  extends  Thread{
     @Override
     public  void  run() {
         System.out.println( "Mythread2 run priority=" + this .getPriority());
     }
}
 
 
class  Mythread1  extends  Thread{
     
     @Override
     public  void  run() {
         System.out.println( "Mythread run priority=" + this .getPriority());
         Mythread2 thread2= new  Mythread2();
         thread2.start();
     }
     
}
 
public  class  Test01 {
 
     public  static  void  main(String[] args)  throws  InterruptedException {
         
         System.out.println( "main thread begin priority=" +Thread.currentThread().getPriority());
                 //Thread.currentThread().setPriority(6);①
         System.out.println( "main thread end priority=" +Thread.currentThread().getPriority());
         Mythread1 thread1= new  Mythread1();
         thread1.start();
     }
     
}
 
结果:
main thread begin priority= 5
main thread end priority= 5
Mythread run priority= 5
Mythread2 run priority= 5

  

可以看到上面几个线程的优先级都为5

现在将①处的代码注释掉后的结果是:

1
2
3
4
main thread begin priority= 5
main thread end priority= 6
Mythread run priority= 6
Mythread2 run priority= 6

  

优先级被更改后再继续继承

9、守护线程:

在java中有两种线程,一种是用户线程,另一种是守护线程。

守护线程是一种特殊的线程,它的特性有“陪伴”的含义,当进程中不存在非守护线程了,则守护线程自动销毁。典型的守护线程就是垃圾回收线程,当进程中没有非守护线程了,则垃圾回收线程也就没有存在的必要了,自动销毁。用个比较通俗的比喻来解释一下:“守护线程”:任何一个守护线程都是整个JVM中所有非守护线程的“保姆”,只要当前JVM实例中存在任何一个非守护线程没有结束,守护线程就在工作,只有当最后一个非守护线程结束时,守护线程才随着JVM一同结束工作。Daemon的作用是为其他线程的运行提供便利服务,守护线程最典型的应用就是GC(垃圾回收器),它就是一个很称职的守护者。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class  Mythread  extends  Thread{
     
     private  int  i= 0 ;
     
     
     @Override
     public  void  run() {
         
         try  {
             while ( true ) {
                 i++;
                 System.out.println( "i=" +(i));
                 Thread.sleep( 1000 );
             }
         } catch (Exception e) {
             e.printStackTrace();
         }
         
     }
     
}
 
public  class  Test01 {
 
     public  static  void  main(String[] args)  throws  InterruptedException {
         
         try  {
             Mythread thread= new  Mythread();
             thread.setDaemon( true );
             thread.start();
             Thread.sleep( 5000 );
             System.out.println( "我离开Thread对象就不再打印了,也就是停止了" );
         } catch (Exception e) {
             e.printStackTrace();
         }
     }
     
}

  

身体和灵魂都要在路上
 
分类:  Java核心基础Java

本系列文章是Java多线程的详解介绍,对多线程还不熟悉的同学可以先去看一下我的这篇博客Java基础系列3:多线程超详细总结,这篇博客从宏观层面介绍了多线程的整体概况,接下来的几篇文章是对多线程的深入剖析。

多线程的常用方法

1、currentThread()方法:

介绍:currentThread()方法可返回该代码正在被哪个线程调用的信息。

示例

例1:

1
2
3
4
5
6
7
8
9
10
public  class  Test01 {
 
     public  static  void  main(String[] args) {
         System.out.println(Thread.currentThread().getName());
     }
     
}
 
结果:
main

  

结果说明,main方法被名为main的线程调用

例2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class  Mythread  extends  Thread{
     
     public  Mythread() {
         System.out.println( "构造方法的打印:" +Thread.currentThread().getName());
     }
     
     @Override
     public  void  run() {
         System.out.println( "run方法的打印:" +Thread.currentThread().getName());
     }
}
 
public  class  Test01 {
 
     public  static  void  main(String[] args) {
         Mythread t= new  Mythread();
         t.start(); //①
     }
     
}
 
结果:
构造方法的打印:main
run方法的打印:Thread- 0

  

从结果可知:Mythread的构造方法是被main线程调用的,而run方法是被名称为Thread-0的线程调用的,run方法是线程自动调用的

现在我们将①处的代码改为t.run(),现在的输出结果如下:

1
2
构造方法的打印:main
run方法的打印:main

  

从结果中我们可以看到两次的结果显示都是main线程调用了方法,因为当你使用t.start()方法的时候是线程自动调用的run()方法,所以输出的是Thread-0,当你直接调用run()方法时,和调用普通方法没有什么区别,所以是main线程调用run()

2、isAlive()方法:

介绍:isAlive()方法的功能是判断当前的线程是否处于活动状态

示例:

例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class  Mythread  extends  Thread{
     
     @Override
     public  void  run() {
         System.out.println( "run ==" + this .isAlive());
     }
     
}
 
public  class  Test01 {
 
     public  static  void  main(String[] args) {
         Mythread thread= new  Mythread();
         System.out.println( "begin ==" +thread.isAlive()); //①
         thread.start(); //②
         System.out.println( "end ==" +thread.isAlive()); //③
     }
     
}
 
结果:
begin == false
end == true
run == true

  

方法isAlive()的作用是测试线程是否处于活动状态。那么什么情况下是活动状态呢?活动状态就是线程已经启动且尚未停止。线程处于正在运行或准备开始运行的状态,就认为线程是存活的

①处代码的结果为false,因为此时线程还未启动;

②处代码调用了run()方法输出结果为run ==true,此时线程处于活动状态;

③处代码的结果为true,有的同学看到这个输出可能会不理解,不是说线程处于活动状态isAlive()方法的结果才是true,现在程序都已经运行结束了为什么还是true?这里的输出结果是不确定的,我们再来看下面一段代码

我们将例1中的代码稍做修改,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public  class  Test01 {
 
     public  static  void  main(String[] args)  throws  InterruptedException {
         Mythread thread= new  Mythread();
         System.out.println( "begin ==" +thread.isAlive()); //①
         thread.start(); //②
         Thread.sleep( 1000 ); //这里加了一行代码,让当前线程沉睡1秒
         System.out.println( "end ==" +thread.isAlive()); //③
     }
     
}
 
结果:
begin == false
run == true
end == false

  

现在我们看到③处的代码结果为end ==false,因为thread对象已经在1秒内执行完毕,而上面代码输出结果为true是因为thread线程未执行完毕。

3、sleep()方法:

介绍:

方法sleep()的作用是在指定的毫秒数内让当前“正在执行的线程”休眠(暂停执行),这个“正在执行的线程”是指this.currentThread()返回的线程。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class  Mythread  extends  Thread{
     
     @Override
     public  void  run() {
         
         try  {
             System.out.println( "run threadName=" + this .currentThread().getName()+ " begin" );
             Thread.sleep( 2000 );
             System.out.println( "run threadName=" + this .currentThread().getName()+ " end" );
             
         catch  (InterruptedException e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
         }
         
     }
     
}
 
public  class  Test01 {
 
     public  static  void  main(String[] args)  throws  InterruptedException {
         Mythread thread= new  Mythread();
         System.out.println( "begin =" +System.currentTimeMillis());
         thread.run(); //①
         System.out.println( "end =" +System.currentTimeMillis());
     }
     
}
 
结果:
begin = 1574660731663
run threadName=main begin
run threadName=main end
end = 1574660733665

  

从结果中可以看出main线程暂停了2秒(因为这里调用的是thread.run())

下面我们将①处的代码改成thread.start(),再来看下运行结果:

1
2
3
4
begin = 1574661491412
end = 1574661491412
run threadName=Thread- 0  begin
run threadName=Thread- 0  end

  

由于main线程与thread线程是异步执行的,所以首先打印的信息为begin和end,而thread线程是随后运行的,在最后两行打印run begin和run end的信息。

4、getId()方法:

介绍:getId()方法的作用是取得线程的唯一标识

示例

1
2
3
4
5
6
7
8
public  class  Test01 {
 
     public  static  void  main(String[] args)  throws  InterruptedException {
         Thread thread=Thread.currentThread();
         System.out.println(thread.getName()+ " " +thread.getId());
     }
     
}<br><br>结果:main  1

  

从运行结果可以看出,当前执行代码的线程名称是main,线程id值为1

5、停止线程:

介绍:停止线程是在多线程开发时很重要的技术点,掌握此技术可以对线程的停止进行有效的处理。停止线程在Java语言中并不像break语句那样干脆,需要一些技巧性的处理。

在java中有三种方法可以停止线程

  1. 使用退出标志,让线程正常退出,也就是当run方法执行完之后终止
  2. 使用stop方法强制终止线程,但是不推荐使用,因为stop和suspend及resume一样,是java废弃的方法
  3. 使用interrupt方法中断线程(推荐使用)

示例:

例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class  Mythread  extends  Thread{
     
     @Override
     public  void  run() {
         
         for ( int  i= 0 ;i< 5000 ;i++) {
             System.out.println( "i=" +(i+ 1 ));
         }
     }
     
}
 
public  class  Test01 {
 
     public  static  void  main(String[] args)  throws  InterruptedException {
         Mythread thread= new  Mythread();
         thread.start();
         Thread.sleep( 2000 );
         thread.interrupt();
     }
     
}

  

运行结果:

从运行结果我们可以看出最后i=500000,调用interrupt方法没有停止线程,那么该如何停止线程呢?

在介绍如何停止线程时,我们先来介绍一下如何判断线程是否处于停止状态

Thread类中提供了两种方法用来判断线程是否停止:

1、this.interrupted():测试当前线程是否已经中断,执行后具有将状态标志清除为false的功能

1
2
3
public  static  boolean  interrupted() {
         return  currentThread().isInterrupted( true );
}

  

2、this.isInterrupted():测试线程Thread对象是否已经中断,但是不清除状态标志

1
2
3
public  boolean  isInterrupted() {
         return  isInterrupted( false );
}

  

读者可以仔细观看一下这两个方法的声明有什么不同?

例2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class  Mythread  extends  Thread{
     
     @Override
     public  void  run() {
         
         for ( int  i= 0 ;i< 5000 ;i++) {
             System.out.println( "i=" +(i+ 1 ));
         }
     }
     
}
 
public  class  Test01 {
 
     public  static  void  main(String[] args)  throws  InterruptedException {
         Mythread thread= new  Mythread();
         thread.start();
         Thread.sleep( 1000 );
         thread.interrupt();
         System.out.println( "是否停止1?=" +thread.interrupted());
         System.out.println( "是否停止2?=" +thread.interrupted());
         System.out.println( "end!" );
     }
     
}

  

结果:

 输出结果显示调用了thread.interrupt()方法后线程并未停止,这也就证明了interrupted()方法的解释:测试当前线程是否已经中断。这个当前线程是main,它从未断过,所以打印的结果是两个false。

如果想让main线程结束该怎么做?

将main方法改成如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public  class  Test01 {
 
     public  static  void  main(String[] args)  throws  InterruptedException {
         Thread.currentThread().interrupt();
         System.out.println( "是否停止1?=" +Thread.interrupted());
         System.out.println( "是否停止2?=" +Thread.interrupted());
         System.out.println( "end!" );
     }
     
}
 
结果:
是否停止 1 ?= true
是否停止 2 ?= false
end!

  

从输出结果我们可以看出,方法interrupted()的确判断出当前线程是否是停止状态。但为什么第2个值是false?

查看一下官方文档的介绍:

测试当前线程是否已经中断。线程的中断状态由该方法清除。换句话说,如果连续两次调用该方法,则第二次调用将返回false(在第一次调用已清除了其中断状态之后,且第二次调用检验完中断状态前,当前线程再次中断的情况除外)。

 文档中说明的非常清楚,interrupted()方法具有清除状态的功能,所以第二次调用interrupted方法返回的值时false。

下面我们来看一下isInterrupted()方法,将main方法改成如下代码:

1
2
3
4
5
6
7
8
9
public  static  void  main(String[] args)  throws  InterruptedException {
         Mythread thread= new  Mythread();
         thread.start();
         thread.interrupt();
         Thread.sleep( 1000 );
         System.out.println( "是否停止1?=" +thread.isInterrupted());
         System.out.println( "是否停止2?=" +thread.isInterrupted());
         System.out.println( "end" );
}<br>结果:<br><br>是否停止 1 ?= true <br>是否停止 2 ?= true <br>end

  

从结果可以看出,方法isInterrrupted()并未清除状态,所以结果为两个true。

例3:在沉睡中停止

当线程调用sleep()方法后再调用interrupt()方法后会有什么结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class  Mythread  extends  Thread{
     
     @Override
     public  void  run() {
         
         try  {
             System.out.println( "run begin" );
             Thread.sleep( 200000 );
             System.out.println( "run end" );
         catch  (InterruptedException e) {
             System.out.println( "在沉睡中被停止,进入catch!" + this .isInterrupted());
             e.printStackTrace();
         }
     }
     
}
 
public  class  Test01 {
 
     public  static  void  main(String[] args)  throws  InterruptedException {
         try  {
             Mythread thread= new  Mythread();
             thread.start();
             Thread.sleep( 200 );
             thread.interrupt();
         } catch (Exception e) {
             System.out.println( "main catch" );
             e.printStackTrace();
         }
         System.out.println( "end!" );
     }
     
}

  

6、暂停线程:

暂停线程意味着此线程还可以恢复运行。在java多线程中,可以使用suspend()方法暂停线程,使用resume()方法恢复线程的执行

例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class  Mythread  extends  Thread{
     
     private  long  i= 0 ;
     public  long  getI() {
         return  i;
     }
     
     public  void  setI( long  i) {
         this .i = i;
     }
     
     @Override
     public  void  run() {
         while ( true ) {
             i++;
         }
     }
     
}
 
public  class  Test01 {
 
     public  static  void  main(String[] args)  throws  InterruptedException {
         
         Mythread thread= new  Mythread();
         thread.start();
         Thread.sleep( 5000 );
         //A段
         thread.suspend();
         System.out.println( "A= " +System.currentTimeMillis()+ " i=" +thread.getI());
         Thread.sleep( 5000 );
         System.out.println( "A= " +System.currentTimeMillis()+ " i=" +thread.getI());
         
         //B段
         thread.resume();
         Thread.sleep( 5000 );
         
         //C段
         thread.suspend();
         System.out.println( "B= " +System.currentTimeMillis()+ " i=" +thread.getI());
         Thread.sleep( 5000 );
         System.out.println( "B= " +System.currentTimeMillis()+ " i=" +thread.getI());
         
     }
     
}

  

结果:


从控制台打印的时间上来看,线程的确被暂停了,而且还可以恢复成运行状态。

7、yield方法:

介绍:yield()方法的作用是放弃当前的CPU资源,将它让给其他的任务去占用CPU执行时间。但放弃的时间不确定,有可能刚刚放弃,马上又获得CPU时间片

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class  Mythread  extends  Thread{
     
     @Override
     public  void  run() {
         long  beginTime=System.currentTimeMillis();
         int  count= 0 ;
         for ( int  i= 0 ;i< 500000 ;i++) {<br>                //Thread.yield();①
             count=count+(i+ 1 );
         }
         long  endTime=System.currentTimeMillis();
         System.out.println( "用时:" +(endTime-beginTime)+ "毫秒!" );
     }
     
}
 
public  class  Test01 {
 
     public  static  void  main(String[] args)  throws  InterruptedException {
         Mythread thread= new  Mythread();
         thread.start();
     }
     
}<br><br>结果:用时: 2 毫秒!

  

现在将①处的代码取消注释,我们再来看一下运行结果:

1
用时: 213 毫秒!

  

将CPU让给其他资源导致速度变慢

8、线程优先级:

介绍:

在操作系统中,线程可以划分优先级,优先级较高的线程得到的CPU资源较多,也就是CPU优先执行优先级较高的线程对象中的任务。

设置线程优先级有助于帮“线程规划器”确定在下一次选择哪一个线程来优先执行。

设置线程的优先级使用setPriority()方法,此方法在JDK的源代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
public  final  void  setPriority( int  newPriority) {
         ThreadGroup g;
         checkAccess();
         if  (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
             throw  new  IllegalArgumentException();
         }
         if ((g = getThreadGroup()) !=  null ) {
             if  (newPriority > g.getMaxPriority()) {
                 newPriority = g.getMaxPriority();
             }
             setPriority0(priority = newPriority);
         }
}

  

在Java中,线程的优先级为1-10这10个等级,如果小于1或大于10,则JDK抛出异常throw new IllegalArgumentException()。

通常高优先级的线程总是先执行完,但是并不是一定的,高优先级和低优先级的线程会交替进行,高优先级执行的次数多一些

线程优先级的继承特性:

在Java中,线程的优先级具有继承性,比如A线程启动B线程,则B线程的优先级与A是一样的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class  Mythread2  extends  Thread{
     @Override
     public  void  run() {
         System.out.println( "Mythread2 run priority=" + this .getPriority());
     }
}
 
 
class  Mythread1  extends  Thread{
     
     @Override
     public  void  run() {
         System.out.println( "Mythread run priority=" + this .getPriority());
         Mythread2 thread2= new  Mythread2();
         thread2.start();
     }
     
}
 
public  class  Test01 {
 
     public  static  void  main(String[] args)  throws  InterruptedException {
         
         System.out.println( "main thread begin priority=" +Thread.currentThread().getPriority());
                 //Thread.currentThread().setPriority(6);①
         System.out.println( "main thread end priority=" +Thread.currentThread().getPriority());
         Mythread1 thread1= new  Mythread1();
         thread1.start();
     }
     
}
 
结果:
main thread begin priority= 5
main thread end priority= 5
Mythread run priority= 5
Mythread2 run priority= 5

  

可以看到上面几个线程的优先级都为5

现在将①处的代码注释掉后的结果是:

1
2
3
4
main thread begin priority= 5
main thread end priority= 6
Mythread run priority= 6
Mythread2 run priority= 6

  

优先级被更改后再继续继承

9、守护线程:

在java中有两种线程,一种是用户线程,另一种是守护线程。

守护线程是一种特殊的线程,它的特性有“陪伴”的含义,当进程中不存在非守护线程了,则守护线程自动销毁。典型的守护线程就是垃圾回收线程,当进程中没有非守护线程了,则垃圾回收线程也就没有存在的必要了,自动销毁。用个比较通俗的比喻来解释一下:“守护线程”:任何一个守护线程都是整个JVM中所有非守护线程的“保姆”,只要当前JVM实例中存在任何一个非守护线程没有结束,守护线程就在工作,只有当最后一个非守护线程结束时,守护线程才随着JVM一同结束工作。Daemon的作用是为其他线程的运行提供便利服务,守护线程最典型的应用就是GC(垃圾回收器),它就是一个很称职的守护者。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class  Mythread  extends  Thread{
     
     private  int  i= 0 ;
     
     
     @Override
     public  void  run() {
         
         try  {
             while ( true ) {
                 i++;
                 System.out.println( "i=" +(i));
                 Thread.sleep( 1000 );
             }
         } catch (Exception e) {
             e.printStackTrace();
         }
         
     }
     
}
 
public  class  Test01 {
 
     public  static  void  main(String[] args)  throws  InterruptedException {
         
         try  {
             Mythread thread= new  Mythread();
             thread.setDaemon( true );
             thread.start();
             Thread.sleep( 5000 );
             System.out.println( "我离开Thread对象就不再打印了,也就是停止了" );
         } catch (Exception e) {
             e.printStackTrace();
         }
     }
     
}

  

猜你喜欢

转载自www.cnblogs.com/xichji/p/11933072.html