首页 > 编程语言 > 详细

Java并发(一):线程

时间:2020-11-09 10:48:21      阅读:23      评论:0      收藏:0      [点我收藏+]


前言:

本文将简单的介绍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并发(一):线程

原文:https://www.cnblogs.com/hbcolorful/p/13947206.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!