简单了解Java编程中线程的创建与守护线程

 更新时间:2015年11月21日 09:26:07   投稿:goldensun  
这篇文章主要介绍了Java编程中线程的创建与守护线程,是Java多线程并发编程的基础,需要的朋友可以参考下

线程的两种创建方式及优劣比较
1、通过实现Runnable接口线程创建
(1).定义一个类实现Runnable接口,重写接口中的run()方法。在run()方法中加入具体的任务代码或处理逻辑。
(2).创建Runnable接口实现类的对象。
(3).创建一个Thread类的对象,需要封装前面Runnable接口实现类的对象。(接口可以实现多继承)
(4).调用Thread对象的start()方法,启动线程
示例代码:

package demo.thread; 
 
public class TreadDemo1 implements Runnable { 
  private int countDown = 10; 
  @Override 
  // 在run方法中定义任务 
  public void run() { 
    while (countDown-- > 0) { 
      System.out.println("#" + Thread.currentThread().getName() + "(" 
          + countDown + ")"); 
    } 
  } 
 
  public static void main(String[] args) { 
    // Runnable中run方法是一个空方法,并不会产生任何线程行为,必须显式地将一个任务附着到线程上 
    TreadDemo1 tt=new TreadDemo1(); 
    new Thread(tt).start(); 
    new Thread(tt).start(); 
    System.out.println("火箭发射前倒计时:"); 
  } 
} 

 运行结果:
火箭发射前倒计时:

#Thread-1(8)
#Thread-1(7)
#Thread-1(6)
#Thread-1(5)
#Thread-1(4)
#Thread-1(3)
#Thread-1(2)
#Thread-1(1)
#Thread-1(0)
#Thread-0(9)

2、通过继承Thread类创建线程
(1).首先定义一个类去继承Thread父类,重写父类中的run()方法。在run()方法中加入具体的任务代码或处理逻辑。
(2).直接创建一个ThreadDemo2类的对象,也可以利用多态性,变量声明为父类的类型。
(3).调用start方法,线程t启动,隐含的调用run()方法。
示例代码:

package demo.thread; 
 
public class ThreadDemo2 extends Thread { 
  private int countDown = 10; 
 
  @Override 
  // 在run方法中定义任务 
  public void run() { 
    while (countDown-- > 0) { 
      System.out.println("#" + this.getName() + "(" + countDown + ")"); 
    } 
  } 
 
  public static void main(String[] args) { 
    new ThreadDemo2().start(); 
    new ThreadDemo2().start(); 
    // 由于start方法迅速返回,所以main线程可以执行其他的操作,此时有两个独立的线程在并发运行 
    System.out.println("火箭发射前倒计时:"); 
  } 
} 

 运行结果:

#Thread-0(9)
#Thread-0(8)
#Thread-0(7)
#Thread-0(6)
#Thread-0(5)
#Thread-0(4)
#Thread-0(3)
#Thread-0(2)
#Thread-0(1)
#Thread-0(0)

火箭发射前倒计时:

#Thread-1(9)
#Thread-1(8)
#Thread-1(7)
#Thread-1(6)
#Thread-1(5)
#Thread-1(4)
#Thread-1(3)
#Thread-1(2)
#Thread-1(1)
#Thread-1(0)

3、两种方式的比较
首先分析两种方式的输出结果,同样是创建了两个线程,为什么结果不一样呢?
使用实现Runnable接口方式创建线程可以共享同一个目标对象 (TreadDemo1 tt=new TreadDemo1();),实现了多个相同线程处理同一份资源。
然后再看一段来自JDK的解释:
Runnable 接口应该由那些打算通过某一线程执行其实例的类来实现。类必须定义一个称为run 的无参数方法。
设计该接口的目的是为希望在活动时执行代码的对象提供一个公共协议。例如,Thread 类实现了Runnable 。激活的意思是说某个线程已启动并且尚未停止。
此外,Runnable 为非 Thread 子类的类提供了一种激活方式。通过实例化某个Thread 实例并将自身作为运行目标,就可以运行实现 Runnable 的类而无需创建 Thread 的子类。大多数情况下,如果只想重写run() 方法,而不重写其他 Thread 方法,那么应使用 Runnable 接口。这很重要,因为除非程序员打算修改或增强类的基本行为,否则不应为该类创建子类。
 
采用继承Thread类方式:
(1)优点:编写简单,如果需要访问当前线程,无需使用Thread.currentThread()方法,直接使用this,即可获得当前线程。
(2)缺点:因为线程类已经继承了Thread类,所以不能再继承其他的父类。
采用实现Runnable接口方式:
(1)优点:线程类只是实现了Runable接口,还可以继承其他的类。在这种方式下,可以多个线程共享同一个目标对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。
(2)缺点:编程稍微复杂,如果需要访问当前线程,必须使用Thread.currentThread()方法。

后台线程(守护线程)
所谓的后台线程,是指在程序运行的时候在后台提供一种通用服务的线程,并且这种线程并不属于程序中不可或缺的部分。因此当所有的非后台线程结束时,程序也就终止了,同时会杀死所有后台线程。反过来说,只要有任何非后台线程(用户线程)还在运行,程序就不会终止。后台线程在不执行finally子句的情况下就会终止其run方法。后台线程创建的子线程也是后台线程。 下面是一个后台线程的示例:

package demo.thread; 
 
import java.util.concurrent.TimeUnit; 
 
public class DaemonDemo implements Runnable { 
  @Override 
  public void run() { 
    try { 
      while (true) { 
        Thread.sleep(1000); 
        System.out.println("#" + Thread.currentThread().getName()); 
      } 
    } catch (InterruptedException e) { 
      e.printStackTrace(); 
    } finally {// 后台线程不执行finally子句 
      System.out.println("finally "); 
    } 
  } 
 
  public static void main(String[] args) { 
    for (int i = 0; i < 10; i++) { 
      Thread daemon = new Thread(new DaemonDemo()); 
      // 必须在start之前设置为后台线程 
      daemon.setDaemon(true); 
      daemon.start(); 
    } 
    System.out.println("All daemons started"); 
    try { 
      TimeUnit.MILLISECONDS.sleep(1000); 
    } catch (InterruptedException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
    } 
  } 
} 

 
运行结果:

All daemons started
#Thread-2
#Thread-3
#Thread-1
#Thread-0
#Thread-9
#Thread-6
#Thread-8
#Thread-5
#Thread-7
#Thread-4

分析:从结果可以看出,十个子线程并没有无线循环的打印,而是在主线程(main())退出后,JVM强制关闭所有后台线程。而不会有任何希望出现的确认形式,如finally子句不执行。

相关文章

  • 利用IDEA社区版创建SpringBoot项目的详细图文教程

    利用IDEA社区版创建SpringBoot项目的详细图文教程

    大家应该都知道Idea社区版本,默认是不能创建SpringBoot项目的,下面这篇文章主要给大家介绍了关于利用IDEA社区版创建SpringBoot项目的详细图文教程,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2023-04-04
  • OAuth2生成token代码备忘实现过程示例

    OAuth2生成token代码备忘实现过程示例

    这篇文章主要为大家介绍了OAuth2生成token代码备忘实现过程示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08
  • java数据结构与算法之双向循环队列的数组实现方法

    java数据结构与算法之双向循环队列的数组实现方法

    这篇文章主要介绍了java数据结构与算法之双向循环队列的数组实现方法,结合实例形式分析了双向循环队列的原理与数组实现技巧,并附带说明了该算法的用途,需要的朋友可以参考下
    2016-08-08
  • 如何使用try-with-resource机制关闭连接

    如何使用try-with-resource机制关闭连接

    这篇文章主要介绍了使用try-with-resource机制关闭连接的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • Mybatis返回插入主键id的方法

    Mybatis返回插入主键id的方法

    这篇文章主要介绍了 Mybatis返回插入主键id的方法,在文章底部给大家补充了Mybatis中insert中返回主键ID的方法,非常不错,需要的朋友可以参考下
    2017-04-04
  • 使用redis的increment()方法实现计数器功能案例

    使用redis的increment()方法实现计数器功能案例

    这篇文章主要介绍了使用redis的increment()方法实现计数器功能案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-11-11
  • springboot单元测试依赖踩坑记录

    springboot单元测试依赖踩坑记录

    这篇文章主要介绍了springboot单元测试依赖踩坑记录及解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • Java OSS批量下载并压缩为ZIP代码实例

    Java OSS批量下载并压缩为ZIP代码实例

    这篇文章主要介绍了Java OSS批量下载并压缩为ZIP代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-09-09
  • Java构造器与传值学习总结

    Java构造器与传值学习总结

    这篇文章主要为大家详细介绍了Java构造器与传值学习总结,文中示例介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • JAVA使用Gson解析json数据实例解析

    JAVA使用Gson解析json数据实例解析

    JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,易于阅读和编写,同时也易于机器解析和生成。接下来通过本文给大家介绍JAVA使用Gson解析json数据实例解析,需要的朋友参考下吧
    2016-03-03

最新评论