《java 核心技术》这本书真的不错,知识点很全面,翻译质量也还不错,本系列博文是对该书中并发章节的一个总结。

什么是线程

  官方解释:线程是操作系统能够进行运算调度的最小单位,包含于进程之中,是进程中的实际运作单位。也就是说线程是代码运行的载体,我们所编写的代码都是在线程上跑的,以一个最简单的 hellowWorld 为例:

public class Main {

    public static void main(String[] args) {
System.out.println("Hello World!");
System.out.println("当前线程名为:"+Thread.currentThread().getName());
System.out.println("当前线程id为:"+Thread.currentThread().getId());
}
}

结果为:

Hello World!
当前线程名为:main
当前线程id为:1

在程序运行时默认会创建一个主线程来执行代码,线程名为:main,线程 id 为 1

什么是多线程

  顾名思义就是多个线程同时运行,提高程序执行速度。单个线程一次只能做一件事,想要提高执行效率有两种途径:

  • 异步。因为大多数时候线程都不是时刻在进行计算,都是在等待 io 操作,那么就可以将等待时间利用起来以提高线程的利用率。这里不做过多讨论,想要进一步了解异步的可以学习 Node.js(原生支持异步)
  • 多线程。一个线程一次只能做一件事,那么多个线程就能同时做多件事了,通过增大线程数来提高执行速度。

如何创建线程

  创建线程有两种方法

  • 继承 Thread 类
  • 实现 runnable 接口

继承 Thread 类

  不推荐本方式来创建线程,原因显而易见:java 不支持多继承,如果继承了 Thread 类就不能再继承其他类了。

  使用继承方式创建线程代码如下:

public class CustomThreadExtendThread extends Thread{

    @Override
public void run() {
String threadName = Thread.currentThread().getName();
long threadId = Thread.currentThread().getId();
System.out.println("创建线程名为:"+threadName+",id为:"+threadId);
} public static void main(String[] args){
Thread thread1 = new CustomThreadExtendThread();
Thread thread2 = new CustomThreadExtendThread();
thread1.start();
thread2.start();
}
}

实现 runnable 接口

  实现接口来创建线程是目前推荐的一种方式,原因也很简单:一个类可以实现多个接口。实现 Runnable 接口并不影响实现类再去实现其他接口。

  使用实现接口方式创建线程代码如下:

public class CustomThreadImplementInterface implements Runnable {
@Override
public void run() {
Thread.currentThread().setName(((Double) Math.random()).toString());
String threadName = Thread.currentThread().getName();
long threadId = Thread.currentThread().getId();
System.out.println("创建线程名为:" + threadName + ",id为:" + threadId);
} public static void main(String[] args) {
Thread thread1 = new Thread(new CustomThreadImplementInterface());
Thread thread2 = new Thread(new CustomThreadExtendThread());
thread1.start();
thread2.start(); //使用lambda表达式,让创建线程更简单
new Thread(() -> {
System.out.println("创建了一个新线程");
}).start();
}
}

  通过查看 Thread 源码可以看到 Thread 类也是 Runnable 接口的一个实现类。

PS:后续代码全部使用 runnable 创建线程

线程状态

  上面只是演示了线程的创建,现在来详细了解线程的状态。在 java 规范中,线程可以有以下 6 种状态:

  • New(新创建)
  • Runnable(可运行)
  • Blocked(阻塞)
  • Waiting(等待)
  • Timed waiting(计时等待)
  • Terminated(被终止)

新创建线程

  当使用 new 操作符创建一个线程时,如 new Thread(r),线程还未开始运行,就属于新创建状态。

可运行线程

  一旦调用 Thread 类的 start 方法,线程就处于可运行状态。

为什么要叫运行状态?

  因为 Java 的规范中并没有将正在 CPU 上运行定义为一个单独的状态。因此处于可运行状态的线程可能正在运行,也可能没有运行,取决于 CPU 的调度策略。

被阻塞线程和等待线程

  当线程处于阻塞或等待状态时,不运行任何代码且消耗最少的资源。直到重新运行。有如下几种途径让线程进入阻塞或等待状态:

  • 当一个线程试图获取一个内部的对象锁,而该锁被其他线程持有
  • 当线程等待另一个线程通知调度器一个条件时,进入等待状态。比如调用 Object.wait 或 Thread.join 方法,或等待 java.util.concurrent 库中的 Lock 或 Condition 时。
  • 当调用计时等待方法时。比如 Thread.sleep,Object.wait,Thread.join,Lock.tryLock 以及 Condition.await

被终止的线程

  线程可由以下两种办法进入终止状态:

  • run 方法的结束而自然死亡
  • 未捕获异常中止了 run 方法而意外死亡

注意: 调用线程的 stop 方法也可以终止线程,但是这个方法已经被弃用,最好不要使用。

线程属性

  线程有各种属性:优先级,守护线程,线程组以及处理未捕获异常处理器。

线程优先级

  java 中,每个线程都有一个优先级。默认情况下,线程继承父线程优先级。也可以调用setPriority方法指定优先级。优先级范围:1(MIN_PRIORITY)-10(MAX_PRIORITY).NORM_PRIORITY 为 5,这些常量定义在 Thread 类中.

注意: 线程优先级时高度依赖于系统的,因此当 java 线程优先级映射到宿主机平台的优先级时,优先级个数可能会变少或者变成 0.比如,Windows 中有 7 个优先级,java 线程映射时部分优先级将会映射到相同的操作系统优先级上。Oracle 为 Linux 编写的 java 虚拟机中,忽略了线程的优先级,所有 java 线程都有相同的优先级。不要编写依赖优先级的代码

守护线程

  通过调用Thread.setDaemon(true)将一个线程转换为守护线程。守护线程唯一的用户是为其他线程提供服务,比如计时线程,定时发送计时信号给其他线程。因此当虚拟机中只有守护线程时,虚拟机就会关闭退出。不要在守护线程中访问任何资源,处理任何业务逻辑

未捕获异常处理器

  线程的 run 方法不能抛出任何受查异常,非受查异常会导致线程终止,除了 try/catch 捕获异常外,还可以通过未捕获异常处理器来处理异常。异常处理器需要实现Thread.UncaughtExceptionHandler接口。

  可以使用线程示例的setUncaughtExceptionHandler()方法为某个线程设置处理器,也可使用Thread.setDefaultUncaughtExceptionHandler()为所有线程设置默认处理器,代码如下:

public class CustomExceptionHandler implements Thread.UncaughtExceptionHandler {

    @Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("捕获到线程"+t.getName()+",异常:" + e.getMessage());
e.printStackTrace();
} public static void main(String[] args) {
Thread.setDefaultUncaughtExceptionHandler(new CustomExceptionHandler());
new Thread(() -> {
throw new RuntimeException("test");
}).start();
}
}

  如果不设置默认处理器且不为独立的线程设置处理器,那么该线程的处理器就为该线程的线程组对象--ThreadGroup(因为线程组对象实现了Thread.UncaughtExceptionHandler接口)。

本篇所用全部代码:github

本篇原创发布于:https://www.tapme.top/blog/detail/2019-04-08-20-52

最全java多线程学习总结1--线程基础的更多相关文章

  1. Java多线程学习笔记之一线程基础

    1.进程与线程 1.1 进程:是正在运行中的程序的实例,一个运行中idea就是一个进程.进程有它自己的地址空间,一般情况下,包括文本区域(text region).数据区域(data region)和 ...

  2. java多线程学习-同步之线程通信

    这个示例是网上烂大街的,子线程循环100次,主线程循环50次,但是我试了很多次,而且从网上找了很多示例,其实多运行几次,看输出结果并不正确.不知道是我转牛角尖了,还是怎么了.也没有大神问,好痛苦.现在 ...

  3. Java多线程学习(四)---控制线程

    控制线程 摘要: Java的线程支持提供了一些便捷的工具方法,通过这些便捷的工具方法可以很好地控制线程的执行 1. join线程控制,让一个线程等待另一个线程完成的方法 2. 后台线程,又称为守护线程 ...

  4. JAVA多线程学习六-守护线程

    java中的守护程序线程是一个服务提供程序线程,它为用户线程提供服务. 它的生命依赖于用户线程,即当所有用户线程都死掉时,JVM会自动终止该线程. 有许多java守护程序线程自动运行,例如 gc,fi ...

  5. JAVA多线程学习五:线程范围内共享变量&ThreadLocal

    一.概念 可以将每个线程用到的数据与对应的线程号存放到一个map集合中,使用数据时从这个集合中根据线程号获取对应线程的数据,就可以实现线程范围内共享相同的变量. 二.代码 Runnable中的run( ...

  6. Java多线程学习(五)线程间通信知识点补充

    系列文章传送门: Java多线程学习(二)synchronized关键字(1) Java多线程学习(二)synchronized关键字(2) Java多线程学习(三)volatile关键字 Java多 ...

  7. Java多线程学习笔记

    进程:正在执行中的程序,其实是应用程序在内存中运行的那片空间.(只负责空间分配) 线程:进程中的一个执行单元,负责进程汇总的程序的运行,一个进程当中至少要有一个线程. 多线程:一个进程中时可以有多个线 ...

  8. Java多线程学习(转载)

    Java多线程学习(转载) 时间:2015-03-14 13:53:14      阅读:137413      评论:4      收藏:3      [点我收藏+] 转载 :http://blog ...

  9. java多线程学习笔记——详细

    一.线程类  1.新建状态(New):新创建了一个线程对象.        2.就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法.该状态的线程位于可运行线程池中, ...

随机推荐

  1. javascript相框echarts插件实现酷立方效果图的人

    最近由于项目需求,我们需要做的一类似网络效应的人立方效果,很多文件中的查询之后.百度发现echarts开源组件非常适合,而加载速度是伟大的.echarts图形主要使用html5这些新功能做,使用can ...

  2. QWidget居中显示(qt窗口坐标原点是在”左上角”的,有图)

    转载请说明出处, 并附上原文链接http://blog.csdn.net/qq907482638/article/details/72189014. 问题描述 在Qt学习过程中,在让QDialog居中 ...

  3. 在vs code中使用dotnet watch run

    只需要在csproj文件中加入一行: <ItemGroup> <PackageReference Include="Microsoft.AspNetCore.App&quo ...

  4. ElasticSearch的基本用法与集群搭建 good

    一.简介 ElasticSearch和Solr都是基于Lucene的搜索引擎,不过ElasticSearch天生支持分布式,而Solr是4.0版本后的SolrCloud才是分布式版本,Solr的分布式 ...

  5. 距离北京奥运还有359天,发布WPF版本的北京2008标志(上)

    原文:距离北京奥运还有359天,发布WPF版本的北京2008标志(上) 效果图: XAML代码:<Canvas Width="343.581055" Height=" ...

  6. wpf之自定义滚动条

    原文:wpf之自定义滚动条 首先我们添加一个带滚动条的textbox控件: <ScrollViewer Height="130" Width="620" ...

  7. python两个整数和浮点的方法来获取值

    /*********************************************************************  * Author  : Samson  * Date   ...

  8. Android新的漏洞的应用程序中的发现!

    最近,趋势科技发现一些Android中的漏洞应用程序内存.来发动攻击.我们调查了两个受影响的应用程序,大家来感受一下: .超过一千万次安装.及在下载页面拥有数十万笔用户留言的生产力应用程序(生产力应用 ...

  9. wpf采用Xps实现文档显示、套打功能

    原文:wpf采用Xps实现文档显示.套打功能 近期的一个项目需对数据进行套打,用户要求现场不允许安装office.页面预览显示必须要与文档完全一致,xps文档来对数据进行处理.Wpf的Document ...

  10. x:Static

    用途:访问代码中的变量等 后台定义一个变量 public partial class GetStaticFromBackgroundCode : Window { public static stri ...