简单了解Java编程中线程的创建与守护线程
作者:goldensun 发布时间:2023-11-25 06:59:52
线程的两种创建方式及优劣比较
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子句不执行。


猜你喜欢
- 本文实例讲述了C#采用FileSystemWatcher实现监视磁盘文件变更的方法。分享给大家供大家参考。具体实现方法如下:简化需求:有一个
- 本文为大家分享了Java实现班级管理系统的具体代码,供大家参考,具体内容如下需求:班级管理系统功能:对学生的信息进行管理1 登录系统 &nb
- Person实体类package com.ljq.domain;public class Person {  
- Android游戏开发中主要的类除了控制类就是显示类,
- Android 11文件管理权限申请Android 11文件管理权限申请,为什么需要这个权限,因为在Android 11后,无法直接在SDc
- 废话不多说了,直奔主题了。需要两个jar包:commons-fileupload.jarCommons IO的jar包(本文使用common
- 在开发应用程序的时候,经常会遇到这样的情况,会在运行时动态根据条件来决定显示哪个View或某个布局。那么最通常的想法就是把可能用到的View
- 1、什么是值传递,什么是引用传递?值传递(pass by value)是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数
- 一段看似平平无奇的代码Classroom classroom = this.getOne( Wrappers.<Class
- Application.Idle()方法表示:当应用程序处于空闲状态时执行相应代码。示例程序1、界面设计:一个简单的Lable控件2、代码u
- 一、Java 8 基本 Base64 基本的加
- 1.打开官网稍微学习一下,了解一下spring cloud是个什么东西,大概有哪些组件等https://spring.io/projects
- 同步客户端套接字示例 下面的示例程序创建一个连接到服务器的客户端。该客户端是用同步套接字生成的,因此挂起客户端应用程
- 效果图:为了使图片浏览器左右无限循环滑动 我们要自定义gallery的adapter如果要想自定义adapter首先要了解这几个方法@Ove
- 目录(?)[-]一扩展javalangThread类二实现javalangRunnable接口三Thread和Runnable的区别四线程状
- using System;using System.Web;using System.Web.Security;namespace Auth
- 最近在做一个需求:从其他系统的ftp目录下载存储图片url的文件,然后读取文件中的url地址,根据地址下载图片后按天压缩成一个包,平均一个地
- 本文是Spring Security系列中的一篇。在上一篇文章中,我们通过实现UserDetailsService和UserDetails接
- 本文介绍了Android Studio 超级简单的打包生成apk,分享给大家,也给自己留个笔记。为什么要打包:apk文件就是一个包,打包就是
- 1. 导入依赖包// retrofit, 基于Okhttp,考虑到项目中经常会用到retrofit,就导入这个了。 compil