一个线程的生命周期

线程是一个动态执行的过程,它也有一个从产生到死亡的过程。

下图显示了一个线程完整的生命周期。

  • 新建状态:

    使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。

  • 就绪状态:

    当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。

  • 运行状态:

    如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。

  • 阻塞状态:

    如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:

    • 等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。

    • 同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。

    • 其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。

  • 死亡状态:

    一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。


线程的优先级

每一个 Java 线程都有一个优先级,这样有助于操作系统确定线程的调度顺序。

Java 线程的优先级是一个整数,其取值范围是 1 (Thread.MIN_PRIORITY ) - 10 (Thread.MAX_PRIORITY )。

默认情况下,每一个线程都会分配一个优先级 NORM_PRIORITY(5)。

具有较高优先级的线程对程序更重要,并且应该在低优先级的线程之前分配处理器资源。但是,线程优先级不能保证线程执行的顺序,而且非常依赖于平台。


Java多线程实现的方式有四种

  • 1.继承Thread类,重写run方法
  • 2.实现Runnable接口,重写run方法,实现Runnable接口的实现类的实例对象作为Thread构造函数的target
  • 3.通过Callable和FutureTask创建线程
  • 4.通过线程池创建线程

    前面两种可以归结为一类:无返回值,原因很简单,通过重写run方法,run方式的返回值是void,所以没有办法返回结果 

    后面两种可以归结成一类:有返回值,通过Callable接口,就要实现call方法,这个方法的返回值是Object,所以返回的结果可以放在Object对象中

方式1:继承Thread类的线程实现方式如下:

public class ThreadDemo1 extends Thread {

	public ThreadDemo1() {
// 编写子类的构造方法,可缺省
} public void run() {
// 编写自己的线程代码
System.out.println(Thread.currentThread().getName());
} public static void main(String[] args) {
ThreadDemo1 threadDemo1 = new ThreadDemo1();
threadDemo1.setName("我是自定义的线程1");
threadDemo1.start();
System.out.println(Thread.currentThread().getName());
}
}

控制台输出:

main
我是自定义的线程1

下表列出了Thread类的一些重要方法:

序号 方法描述
1 public void start()

使该线程开始执行;Java 虚拟机调用该线程的 run 方法。
2 public void run()

如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。
3 public final void setName(String name)

改变线程名称,使之与参数 name 相同。
4 public final void setPriority(int priority)

 更改线程的优先级。
5 public final void setDaemon(boolean on)

将该线程标记为守护线程或用户线程。
6 public final void join(long millisec)

等待该线程终止的时间最长为 millis 毫秒。
7 public void interrupt()

中断线程。
8 public final boolean isAlive()

测试线程是否处于活动状态。

测试线程是否处于活动状态。 上述方法是被Thread对象调用的。下面的方法是Thread类的静态方法。

序号 方法描述
1 public static void yield()

暂停当前正在执行的线程对象,并执行其他线程。
2 public static void sleep(long millisec)

在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。
3 public static boolean holdsLock(Object x)

当且仅当当前线程在指定的对象上保持监视器锁时,才返回 true。
4 public static Thread currentThread()

返回对当前正在执行的线程对象的引用。
5 public static void dumpStack()

将当前线程的堆栈跟踪打印至标准错误流。

方式2:通过实现Runnable接口,实现run方法,接口的实现类的实例作为Thread的target作为参数传入带参的Thread构造函数,通过调用start()方法启动线程:

public class ThreadDemo2 implements Runnable {

	@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName()
+ "-->我是通过实现接口的线程实现方式!");
} public static void main(String[] args) {
System.out.println(Thread.currentThread().getName());
Thread t1 = new Thread(new ThreadDemo2());
t1.start();
}
}

控制台输出:

main
Thread-0-->我是通过实现接口的线程实现方式!

方式3:通过Callable和FutureTask创建线程 

a:创建Callable接口的实现类 ,并实现Call方法 

b:创建Callable实现类的实现,使用FutureTask类包装Callable对象,该FutureTask对象封装了Callable对象的Call方法的返回值 

c:使用FutureTask对象作为Thread对象的target创建并启动线程 

d:调用FutureTask对象的get()来获取子线程执行结束的返回值

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask; public class ThreadDemo3 {
public static void main(String[] args) {
// TODO Auto-generated method stub System.out.println(Thread.currentThread().getName()); Callable<Object> oneCallable = new Tickets<Object>();
FutureTask<Object> oneTask = new FutureTask<Object>(oneCallable);
Thread t = new Thread(oneTask);
t.start();
}
} class Tickets<Object> implements Callable<Object> {
// 重写call方法
@Override
public Object call() throws Exception {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName()
+ "-->我是通过实现Callable接口通过FutureTask包装器来实现的线程");
return null;
}
}

控制台输出:

main
Thread-0-->我是通过实现Callable接口通过FutureTask包装器来实现的线程

方式4:通过线程池创建线程

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class ThreadDemo4 {
private static int POOL_NUM = 10; // 线程池数量 public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName());
ExecutorService executorService = Executors.newFixedThreadPool(5);
for (int i = 0; i < POOL_NUM; i++) {
RunnableThread thread = new RunnableThread();
executorService.execute(thread);
}
// 关闭线程池
executorService.shutdown();
} }

控制台输出:

main
通过线程池方式创建的线程:pool-1-thread-1
通过线程池方式创建的线程:pool-1-thread-3
通过线程池方式创建的线程:pool-1-thread-2
通过线程池方式创建的线程:pool-1-thread-4
通过线程池方式创建的线程:pool-1-thread-1
通过线程池方式创建的线程:pool-1-thread-5
通过线程池方式创建的线程:pool-1-thread-3
通过线程池方式创建的线程:pool-1-thread-3
通过线程池方式创建的线程:pool-1-thread-3
通过线程池方式创建的线程:pool-1-thread-3

ExecutorService、Callable都是属于Executor框架。返回结果的线程是在JDK1.5中引入的新特征,还有Future接口也是属于这个框架,有了这种特征得到返回值就很方便了。 

通过分析可以知道,他同样也是实现了Callable接口,实现了Call方法,所以有返回值。这也就是正好符合了前面所说的两种分类

执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callable任务返回的Object了。get方法是阻塞的,即:线程无返回结果,get方法会一直等待。

再介绍Executors类:提供了一系列工厂方法用于创建线程池,返回的线程池都实现了ExecutorService接口。

  • public static ExecutorService newFixedThreadPool(int nThreads) 

    创建固定数目线程的线程池。
  • public static ExecutorService newCachedThreadPool() 

    创建一个可缓存的线程池,调用execute 将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。
  • public static ExecutorService newSingleThreadExecutor() 

    创建一个单线程化的Executor。
  • public static ScheduledExecutorService newScheduledThreadPool(int 

    corePoolSize) 

    创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代Timer类。
  • ExecutoreService提供了submit()方法,传递一个Callable,或Runnable,返回Future。如果Executor后台线程池还没有完成Callable的计算,这调用返回Future对象的get()方法,会阻塞直到计算完成。

java 多线程实现的四种方式的更多相关文章

  1. JAVA多线程实现的四种方式

    Java多线程实现方式主要有四种:继承Thread类.实现Runnable接口.实现Callable接口通过FutureTask包装器来创建Thread线程.使用ExecutorService.Cal ...

  2. 【转】JAVA多线程实现的四种方式

    原文地址:http://www.cnblogs.com/felixzh/p/6036074.html Java多线程实现方式主要有四种:继承Thread类.实现Runnable接口.实现Callabl ...

  3. JAVA多线程实现的四种方式(转自https://www.cnblogs.com/felixzh/p/6036074.html)

    Java多线程实现方式主要有四种:继承Thread类.实现Runnable接口.实现Callable接口通过FutureTask包装器来创建Thread线程.使用ExecutorService.Cal ...

  4. 关于Java多线程(JAVA多线程实现的四种方式)

    Java多线程实现方式主要有四种:继承Thread类.实现Runnable接口.实现Callable接口通过FutureTask包装器来创建Thread线程.使用ExecutorService.Cal ...

  5. JAVA解析XML的四种方式

    java解析xml文件四种方式 1.介绍 1)DOM(JAXP Crimson解析器) DOM是用与平台和语言无关的方式表示XML文档的官方W3C标准.DOM是以层次结构组织的节点或信息片断的集合.这 ...

  6. java 遍历Map的四种方式

      java 遍历Map的四种方式 CreationTime--2018年7月16日16点15分 Author:Marydon 一.迭代key&value 第一种方式:迭代entrySet 1 ...

  7. Java创建线程的四种方式

    Java创建线程的四种方式 1.继承Thread类创建线程 定义Thread类的子类,并重写该类的run方法,run()方法的内容就是该线程执行的内容 创建Thread子类的实例,即创建了线程对象. ...

  8. 如何实现有返回值的多线程 JAVA多线程实现的三种方式

    可返回值的任务必须实现Callable接口,类似的,无返回值的任务必须Runnable接口.执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callable ...

  9. java线程实现的四种方式

    java多线程的实现可以通过以下四种方式 1.继承Thread类,重写run方法 2.实现Runnable接口,重写run方法 3.通过Callable和FutureTask创建线程 4.通过线程池创 ...

随机推荐

  1. Shell05--函数应用

    目录 Shell05---函数应用 1. 函数基本概述 2. 函数基本使用 3. 函数参数传递 4. 函数状态返回 5. 函数场景示例 Shell05---函数应用 1. 函数基本概述 01. 什么是 ...

  2. css盒子模型的宽度不包括margin

    看到教程上和一些博客上盒子模型的宽度 = content + padding + margin + border,应该是不包括margin的 <!DOCTYPE html> <htm ...

  3. 【串线篇】Mybatis之动态sql

    一.if标签 <select id="getTeacherByCondition" resultMap="teacherMap"> select * ...

  4. 人生苦短_我用Python_configparser/yaml对配置文件读取/写入操作_010

    第一,我们先开始安装yaml库,configparser是自带库,yaml库是针对读取yml文件,configparser现阶段我只用于读取conf文件 首先:1)对象文件为:data.yml,下面的 ...

  5. 神经网络学习笔记(二):feedforward和feedback

    维基百科解释: Feed-forward, sometimes written feedforward, is a term describing an element or pathway with ...

  6. 抽象abstract

    1):一个类如果有抽象方法,这个类一定是抽象类.抽象类不一定有抽象方法.抽象方法是以分号结束.不是以{}. 抽象方法也不提供实现代码. 2):任何拓展抽象类的类都必须实现超类的所有抽象方法.除非子类也 ...

  7. C++ string.replace的使用

    //下面是一个检查一个字符串中是否有'.'的函数,该函数将找到的'.'转化为'_'. inline void checkName(string& name) { std::; while (s ...

  8. 简记 jQuery 插件模板

    /** * @lisence jquery plugin demo v1.0.0 * * author: Jeremy Yu * * description: * this is a jquery p ...

  9. python最近邻分类器KNN算法

    1. KNN算法 邻近算法,或者说K最近邻(kNN,k-NearestNeighbor)分类算法是数据挖掘分类技术中最简单的方法之一.所谓K最近邻,就是k个最近的邻居的意思,说的是每个样本都可以用它最 ...

  10. python中常犯错误之字符串列表下标问题

    下标用得是中括号[] 不是小括号() 1,python中的小括号( ):代表tuple元组数据类型,元组是一种不可变序列.创建方法很简单,大多时候都是用小括号括起来的. 2.python中的中括号[ ...