【多线程学习笔记2】线程的创建与启动

简介: 【多线程学习笔记2】线程的创建与启动

1 线程的创建与启动



Java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。


1.1 继承Thread类创建线程类


通过继承Thread类来创建并启动多线程的步骤如下:


(1)定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务,因此把run()方法称为线程执行体。


(2)创建Thread子类的实例,即创建了线程对象。


(3)调用线程对象的start()方法来启动该线程。


注意:


(1)进行多线程编程时,不要忘记了Java程序运行时默认的主线程,main()方法的方法体就是主线程的线程执行体。


(2)使用继承Thread类的方法来创建线程类时,因为程序每次创建线程对象时都需要创建一个Thread子类的实例对象,所以多个线程之间无法共享线程类的实例变量。


1.2 实现Runnable接口创建线程类


使用Runnable接口来创建并启动多线程的步骤如下:


(1)定义Runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体就是该线程的线程执行体。


(2)创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。


(3)调用线程对象的start()方法来启动该线程。


注意:


(1)Runnable对象仅仅作为Thread对象的target,Runnable实现类里包含的run()方法仅作为线程执行体。而实际的线程对象依然是Thread实例,只是该Thread线程负责执行其target的run()方法。


(2)采用Runnable接口的方式创建的多个线程可以共享线程类的实例变量,这是因为在这种方式下,程序所创建的Runnable对象只是线程的target,而多个线程可以共享同一个target,所以多个线程可以共享同一个线程类(实际上是线程的target类)的实例变量。


1.3 使用Callable和Future创建线程


通过实现Runnable接口创建多线程时,Thread类的作用就是把run()方法包装成线程执行体。


也许受此启发,从Java 5开始,Java提供了Callable接口,这个接口像是Runnable接口的增强,因为Callable接口提供了一个call()方法作为线程执行体,同时call()方法可以有返回值,而且可以声明并抛出异常。


同时Java 5提供了Future接口来代表Callable接口里call()方法的返回值,并为Future接口提供了一个FutureTask实现类,该实现类实现了Future接口,并实现了Runnable接口,也就是说它可以作为Thread类的target。


创建并启动有返回值的线程的步骤如下:


(1)创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,且该call()方法有返回值,再创建Callable实现类的实例。


(2)使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。


(3)使用FutureTask对象作为Thread对象的target创建并启动新线程。


(4)调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。


1.4 创建线程的三种方式对比


通过继承Thread类或实现Runnable、Callable接口都可以实现多线程,不过实现Runnable接口与实现Callable接口的方式基本相同,只是Callable接口里定义的方法有返回值,可以声明抛出异常而已,所以这两个可以归为一类。那这种方式与继承Thread方式之间的主要差别如下。


采用实现Runnable、Callable接口的方式创建多线程的优缺点:


(1)线程类只是实现了Runnable接口或Callable接口,还可以继承其他类。


(2)这种方式下,多个线程可以共享同一个target对象,非常适合多个相同线程处理同一份资源的情况。


(3)劣势是编程稍显复杂,访问当前线程,必须使用Thread.currentThread()方法。

采用继承Thread类的方式创建多线程的优缺点:


(1)编写简单,若需要访问当前线程,无须使用Thread.currentThread()方法,直接使用this即可获得当前线程。


(2)劣势是,线程类已经继承了Thread类,就不能再继承其他父类了。


也是因为上面优劣势,一般是推荐采用实现Runnable接口、Callable接口的方式来创建多线程。对于不需要返回值的就用实现Runnable接口方式,对于需要返回值的就用实现Callable方式来创建。



写在最后的话:


搞开发这么多年了,多线程也用了蛮多了,对于多线程创建和启动的内容也学过很多遍了,但一直局限于应付面试,始终是有点蒙圈的。另外毕竟现在用多线程,都是依赖线程池,我是感觉很少自己直接去new一个线程对象了,所以之前即使有用到,也更多时候都是用的懵懵的。


这次再次学习并整理一下笔记,其实也是受了面试的启发。话说再一次学习,并回顾自己的开发经验,还是很大收获的。总结一下,也方便自己日后再复习回顾吧。

相关文章
|
5天前
|
设计模式 安全 Java
Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
18 1
|
5天前
|
设计模式 存储 安全
Java面试题:设计一个线程安全的单例类并解释其内存占用情况?使用Java多线程工具类实现一个高效的线程池,并解释其背后的原理。结合观察者模式与Java并发框架,设计一个可扩展的事件处理系统
Java面试题:设计一个线程安全的单例类并解释其内存占用情况?使用Java多线程工具类实现一个高效的线程池,并解释其背后的原理。结合观察者模式与Java并发框架,设计一个可扩展的事件处理系统
14 1
|
3天前
|
缓存 Linux 编译器
【Linux】多线程——线程概念|进程VS线程|线程控制(下)
【Linux】多线程——线程概念|进程VS线程|线程控制(下)
11 0
|
3天前
|
存储 Linux 调度
【Linux】多线程——线程概念|进程VS线程|线程控制(上)
【Linux】多线程——线程概念|进程VS线程|线程控制(上)
14 0
|
5天前
|
设计模式 并行计算 安全
Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
10 0
|
5天前
|
设计模式 安全 NoSQL
Java面试题:结合单例模式与Java内存管理,设计一个线程安全的单例类?分析Java多线程工具类ExecutorService与Java并发工具包中的工具类,设计一个Java并发框架的分布式锁实现
Java面试题:结合单例模式与Java内存管理,设计一个线程安全的单例类?分析Java多线程工具类ExecutorService与Java并发工具包中的工具类,设计一个Java并发框架的分布式锁实现
12 0
|
5天前
|
存储 安全 Java
Java面试题:假设你正在开发一个Java后端服务,该服务需要处理高并发的用户请求,并且对内存使用效率有严格的要求,在多线程环境下,如何确保共享资源的线程安全?
Java面试题:假设你正在开发一个Java后端服务,该服务需要处理高并发的用户请求,并且对内存使用效率有严格的要求,在多线程环境下,如何确保共享资源的线程安全?
11 0
|
7天前
|
Java
实现Java多线程中的线程间通信
实现Java多线程中的线程间通信
|
7天前
|
Java
实现Java多线程中的线程间通信
实现Java多线程中的线程间通信
|
5天前
|
Java 开发者
Java面试题:Java内存管理精要与多线程协同策略,Java内存管理:堆内存、栈内存、方法区、垃圾收集机制等,多线程编程的掌握,包括线程创建、同步机制的原理
Java面试题:Java内存管理精要与多线程协同策略,Java内存管理:堆内存、栈内存、方法区、垃圾收集机制等,多线程编程的掌握,包括线程创建、同步机制的原理
10 0