前言:

本文将简单的介绍JAVA并发中的线程。

操作系统的多任务(multitasking):计算机在同一刻运行多个程序的能力,即并发。并发执行的进程数目并不是由CPU数目制约的,操作系统将CPU时间片给每一个进程,给人并行处理的感觉。多线程程序在较低层次扩展了多任务的概念:一个程序可以同时处理多个任务。通常,每一个任务称为一个进程。

进程与线程的区别:本质的区别在于每一个进程拥有自己的一整套变量,而线程共享数据。共享数据会在同步时带来风险,然而共享变量使线程之间的通信比进程之间的通信更有效、更容易。与进程相比,线程更加“轻量级”,创建、撤销一个线程比启动新进程的开销要小得多。

一、什么是线程

单独的线程中执行一个任务的简单过程:

1)将任务代码移到实现了Runnable接口的类中:Runnable接口十分简单,只需要实现一个run方法

public  interface Runnable{

   void run();

}

2)由Runnable创建一个Thread对象

Thread thread = new Thread(runnable);

3)启动线程 thread.start();

不要调用Tread类或Runnable对象的run方法。直接调用run方法,只会执行一个线程中的任务,而不会启动新线程。应该调用Thread.run()方法。这样将会创建一个新线程来执行run方法。

二、中断线程

线程终止:当线程的run方法执行方法体中最后一条语句时,并经由执行return语句返回时,或者出现了在方法中没有捕获的异常时,线程终止。在早期Java版本中,有一个stop方法可以被其他线程调用它终止线程,这方法已被弃用,不推荐使用。

现在没有强制停止线程的方法,但可以通过interrupt(中断)方法发送请求终止线程。当线程调用这方法是,线程的中断状态将被置位,这是每一个线程都具有的boolean标志。每个线程都会不时的检查这个标志,以判断线程是否被请求中断。

想要知道当前线程是否被置位,首先应调用静态的Thread.currentThread方法来获得当前线程,然后调用isInterrupt方法:

while(!Thread.currentThread().isInterrupt() && more work to do){
do more work;
}

但是,当一个线程被阻塞,就无法检测中断状态。当阻塞和中断请求碰撞在一起时,会产生InterruptedException。当在一个被阻塞的的线程(线程调用sleep或wait会被阻塞)上调用interrupt时,阻塞调用将会被InterruptedException中断。

没有任何语言方面的需求要求一个被中断的线程应该终止。中断一个线程不过是引起它的注意。被中断的线程可以决定如何响应中断。某些重要的线程应该处理完异常后,继续执行,而不会理会中断。但更普遍的情况是,线程简单的将中断作为一个终止的请求。这种现成的run方法如下:

Runable r = () ->{
try{
...
while(!Thread.currentThread().isInterrupt() && more work to do){
do more work;
}
}catch(InterruptedException e){
//thread was interrupted during sleeo or wiat
}finally{
//cleanup,if required
}
//exiting thr run method terminates the thread
}

如果在每次工作迭代之后都调用sleep方法(或其他的可中断方法),inInterrupt检测既没有必要也没有用处。如果在中断状态被置位是调用sleep方法,线程不会休眠。相反,它将会清除这一状态并抛出InterruptedException异常。

相似的方法:interruptedisInterrupt

interrupted方法是一个静态方法,它检测当前的线程是否被中断,调用interrupted方法会清除该线程的中断状态。

isInterrupt方法是一个实例方法,可用来检测是否有线程被中断,调用这个方法不会改变中断状态。

s

  • void interrupt()

    向线程发送中断请求。将线程中断状态设置为true。如果当前线程被sleepwait调用阻塞,那么InterruptedException异常被抛出

  • static boolean interrupted()

    测试当前线程是否被中断,静态方法。调用这方法会产生另一作用,它将当前线程的中断状态重置为false。

  • boolean isInterrupt()

    测试线程是否被终止,不会改变中断状态。

  • static Thread currentThread()

    返回代表当前执行线程的Thread对象。

三、线程状态

线程有六种状态:

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

通过调用getState方法可确定一个线程的当前状态

  1. 新建状态

    ​ 当new Thread一个新线程时,改线程还没有还是运行,意味这它的状态是new,当线程处于这一状态时,程序不会开始执行线程中的代码。

    Thread thread = new Thread(runnable)

  2. 可运行线程

    ​ 当调用线程的start方法,线程处于runnable可运行状态。要注意,一个可运行的线程可能正在运行也可能没有运行,线程的运行取决于操作系统给线程提供运行的时间。系统会从处于可运行状态的线程队列中调度线程,为其提供CPU时间片。

    ​ 我们将这一状态的线程称为可运行而不是运行。一旦一个线程开始运行,它不必始终保持运行。运行中的线程被中断,为的是让其他线程获得运行机会。

    ​ 线程调度的细节依赖于操作系统提供的服务。现在所有的桌面以及服务器操作系统都使用抢占式调度。抢占式调度系统给每一个可运行线程一个时间片来执行程序。当时间片用完,操作系统剥夺该线程的运行权,并给另一个线程运行机会。在选择下一个线程时,操作系统还会考虑线程的优先级。

  3. 被阻塞和等待线程

    ​ 当线程处于被阻塞或等待状态时,它不运行任何代码且消耗最少的资源。

    • 当一个线程试图获取一个内部的对象锁(而不是java.util.concurrent库中的锁),而该锁被其他线程持有,则该线程进入阻塞状态。只有当该锁被持有的线程释放时,所有请求该锁的线程变为非阻塞状态,并竞争该锁。
    • 当线程等待另一个线程通知调度器的一个条件时,它自己进入等待状态。在调用Object.wait方法或Thread,jion方法,或者是等待java.util.concurrent库中的LockCondition时,就会出现线程等待。
    • 有几个方法中有一个超时参数。调用他们导致线程进入计时等待状态。这一状态将保持到超时期满或者收到适当的通知。
  4. 被终止的线程

    线程有如下两个原因之一而被终止:

    • 因为run方法正常退出而自然死亡

    • 因为一个没有捕获的异常终止了run方法而意外死亡

四、线程属性

线程的属性包括:线程优先级,守护线程,线程组以及处理未捕获异常的处理器。

  • 线程优先级

    ​ 在Java中,每一个线程有一个优先级,默认情况加,一个线程继承它的父线程的优先级。

    ​ 可用setPriority方法提高或降低任何一个线程的优先级。。可以将优先级设置在MIN_PRIORITY(1)与MAX_PRIORITY(10)之间的任何值。NORM_PRIORITY被定义为5。每当线程调度器有机会选择新线程时,它首先选择具有较高优先级的线程。但是,线程的优先级是高度依赖于操作系统的。当虚拟机依赖于宿主机平台的线程实现机制时,Java线程的优先级被映射到宿主机平台的优先级上。

    ​ 在设置线程优先级时,要防止线程饿死。每当调度器决定运行一个新线程时,首先会在具有高优先级的线程中进行选择,尽管这样会使低优先级的线程完全饿死。

  • 守护线程

    通过调用:

    t.setDaemon(true);

    将线程设置为守护线程。

    守护线程的唯一作用就是为其他线程提供服务。当只剩下守护线程时。虚拟机就会退出。

  • 未捕获异常处理器

    ​ 线程run方法不能抛出任何的受查异常,而受查异常又会导致线程终止,此时县城就死亡了。有有种办法,不需要任何catch子句来处理被传播的异常。在线程死亡之前,异常被传递到一个用于捕获异常的处理器。

    ​ 捕获异常的处理器必须属于一个实现Thread.UncaughtExceptionHandler接口的类,接口内只有一个方法。

    void uncaughtException(Thread t, Throwable e);

    ​ 可以用setUncaughtExceptionHandler方法为任何线程安装处理器。也可以用setDefauktUncaughtHandler为所有线程安装一个默认的处理器。如果没有,默认的处理器为空。

Java并发(一):线程的更多相关文章

  1. Java 并发 中断线程

    Java 并发 中断线程 @author ixenos 对Runnable.run()方法的三种处置情况 1.在Runnable.run()方法的中间中断它 2.等待该方法到达对cancel标志的测试 ...

  2. Java 并发编程 | 线程池详解

    原文: https://chenmingyu.top/concurrent-threadpool/ 线程池 线程池用来处理异步任务或者并发执行的任务 优点: 重复利用已创建的线程,减少创建和销毁线程造 ...

  3. java并发编程 线程基础

    java并发编程 线程基础 1. java中的多线程 java是天生多线程的,可以通过启动一个main方法,查看main方法启动的同时有多少线程同时启动 public class OnlyMain { ...

  4. Java并发1——线程创建、启动、生命周期与线程控制

    内容提要: 线程与进程 为什么要使用多线程/进程?线程与进程的区别?线程对比进程的优势?Java中有多进程吗? 线程的创建与启动 线程的创建有哪几种方式?它们之间有什么区别? 线程的生命周期与线程控制 ...

  5. java并发:线程同步机制之Volatile关键字&原子操作Atomic

    volatile关键字 volatile是一个特殊的修饰符,只有成员变量才能使用它,与Synchronized及ReentrantLock等提供的互斥相比,Synchronized保证了Synchro ...

  6. java并发:线程池、饱和策略、定制、扩展

    一.序言 当我们需要使用线程的时候,我们可以新建一个线程,然后显式调用线程的start()方法,这样实现起来非常简便,但在某些场景下存在缺陷:如果需要同时执行多个任务(即并发的线程数量很多),频繁地创 ...

  7. java并发:线程同步机制之Lock

    一.初识Lock Lock是一个接口,提供了无条件的.可轮询的.定时的.可中断的锁获取操作,所有加锁和解锁的方法都是显式的,其包路径是:java.util.concurrent.locks.Lock, ...

  8. Java并发编程:线程间通信wait、notify

    Java并发编程:线程间协作的两种方式:wait.notify.notifyAll和Condition 在前面我们将了很多关于同步的问题,然而在现实中,需要线程之间的协作.比如说最经典的生产者-消费者 ...

  9. Java并发编程:线程和进程的创建(转)

    Java并发编程:如何创建线程? 在前面一篇文章中已经讲述了在进程和线程的由来,今天就来讲一下在Java中如何创建线程,让线程去执行一个子任务.下面先讲述一下Java中的应用程序和进程相关的概念知识, ...

  10. Java并发3-多线程面试题

    1) 什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位.程序员可以通过它进行多处理器编程,你可以使用多线程对运算密集型任务提速. 2) 线程和进程有什 ...

随机推荐

  1. Linux系统编程—信号集操作函数

    先来回顾一下未决信号集是怎么回事. 信号从产生到抵达目的地,叫作信号递达.而信号从产生到递达的中间状态,叫作信号的未决状态.产生未决状态的原因有可能是信号受到阻塞了,也就是信号屏蔽字(或称阻塞信号集, ...

  2. 01 How does C Programming work ? C语言如何工作?

    where is C used ? C 语言的应用场景 C is widely used C语言被广泛应用于: For creating desktop applications 用于创建桌面应用程序 ...

  3. javaFX 在窗口的标题栏显示当前时间,1秒更新一次时间

    例1:在窗口的标题栏显示当前时间,1秒更新一次时间 1 import java.text.DateFormat; 2 import java.text.SimpleDateFormat; 3 impo ...

  4. devops-jenkins基于角色的权限管理RBAC

    一. devops-jenkins基于角色的权限管理RBAC 1 安装角色的rbac角色管理  1.1) 点击系统管理 1.2) 选择插件管理 1.3) 选择可选插件,输入role搜索 1.4) 选择 ...

  5. JS关闭chorme页面

    百度到的很多答案都失效了,这是收集一位博主的(https://www.jianshu.com/p/9dc2752194b8),目前可以使用. 代价是打开一个空白页面,能实现无提示关闭当前页面.不需要是 ...

  6. 【C语言编程学习笔记】利用462字节代码实现雅虎logo ACSII 动画!

    ACSII 动画演示:   不过本文介绍的是另一个作品:c 代码实现雅虎 logo ACSII 动图. 运行后,你将会看到:   它是一个 20fps.抗锯齿的 Yahoo! logo ASCII 动 ...

  7. spring boot: 从配置文件中读取数据的常用方法(spring boot 2.3.4)

    一,从配置文件中读取数据有哪些方法? 通常有3种用法: 1,直接使用value注解引用得到配置项的值 2,  封装到Component类中再调用 3,  用Environment类从代码中直接访问 生 ...

  8. spring boot:redis+lua实现生产环境中可用的秒杀功能(spring boot 2.2.0)

    一,秒杀需要具备的功能: 秒杀通常是电商中用到的吸引流量的促销活动方式 搭建秒杀系统,需要具备以下几点: 1,限制每个用户购买的商品数量,(秒杀价格为吸引流量一般会订的很低,不能让一个用户全部抢购到手 ...

  9. swoole创建进程

    <?php /** * Created by PhpStorm. * User: mac * Date: 2020/4/23 * Time: 21:57 */ use Swoole\Proces ...

  10. python保存图片

    #coding=utf-8 import requests url ="https://images.pexels.com/photos/1181767/pexels-photo-11817 ...