zoukankan      html  css  js  c++  java
  • Java多线程详述

    线程概述
    操作系统支持同时运行多个任务,每个任务都是一个程序,每个运行中的程序就是一个进程。
    当一个程序运行时,内部可能包含多个顺序执行流,每个顺序执行流就是一个线程。
     
    1.线程和进程
    进程是系统进行资源分配和调度的一个独立单位,一般而言,进程包括如下三个特征:
    1、独立性:进程是系统中独立存在的实体,它可以拥有自己独立的资源,每一个进程都拥有自己的私有的地址空间。在没有经过进程本身允许的情况下,一个用户进程不可以直接访问其它进程的地址空间。
    2、动态性:进程和程序的区别在于,程序只是一个静态的指令集合,而进程是一个正在系统中活动的指令集合。在进程中加入了时间的概念。进程具有自己的生命周期和各种不同的状态,这些概念在程序中都是不具备的。
    3、并发性:多个进程可以在单个处理器上并发执行,多个进程之间不会相互影响。
     
    并发性和并行性区别:
    并行指在同一时刻,有多条指令在多个处理器上同时执行;
    并发指在同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行,使得宏观上具有多个进程同时执行的效果。
     
    线程是进程的执行单元,是进程的组成部分,一个进程可以拥有多个线程。线程可以拥有自己的堆栈、自己的程序计数器和自己的局部变量,但不拥有系统资源。它可以与其它线程共享父进程的资源。
    线程是独立运行的,它并不知道进程中是否还有其他线程存在。线程的执行是抢占式的,也就是说,当前运行的线程在任何时候都可能被挂起,以便另外一个线程可以运行。
    一个线程可以创建和撤销另一个线程,同一个进程中的多个线程之间可以并发执行。
     
    使用多线程的优点:
    1、进程之间不能共享内存,但线程之间共享内存很容易。
    2、系统创建进程时需要为该进程重新分配系统资源,但创建线程代价则小得多。因此使用多线程来实现实现多任务并发比多进程效率更高。
    3、Java语言内置了多线程功能支持,而不是单纯地作为底层操作系统的调度方式,从而简化了Java的多线程编程。
     
    2.线程的创建和启动
    Java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。每个线程的作用是完成一定的任务,实际上是执行一段程序流(一段顺序执行的代码)。Java使用线程执行体来代表这段程序流。
     
    一、继承Thread类创建线程类
    (1)、定义Thread类的子类,并重写该类的run()方法,该run()方法的方法执行体就代表了线程需要完成的任务。因此run()方法就称为线程执行体。
    (2)、创建Thread子类的实例,即创建线程对象。
    (3)、调用线程对象的start()方法来启动该线程。
    注意:使用继承Thread类的方法来创建线程类的时候,多个线程之间无法共享线程类的实例变量。
     
    二、实现Runnable接口创建线程类
    (1)、定义Runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。
    (2)、创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。
    注意:Runnable对象仅仅作为Thread对象的target,Runnable实现类里包含的run()方法仅作为线程执行体。而实际的线程对象依然是Thread实例,只是该Thread线程负责执行其target的run()方法。
    (3)、调用线程对象的start()方法来启动该线程。
     
    对比两种方式:通过继承Thread类来获得当前线程对象比较简单,直接使用this就行了,但是通过实现Runnable接口来获得当前线程对象则必须使用Thread.currentThread()方法。
     
    三、使用Callable和Future创建线程
    Callable接口提供了一个call()方法可以作为线程执行体,但call()方法比run()方法功能更加强大。
    1、call()方法可以有返回值。
    2、call()方法可以声明抛出异常。
    Java5提供了Future接口来代表Callable接口里call()方法的返回值,并为Future接口提供了一个FutureTask实现类,该实现类实现了Future接口,并实现了Runnable接口----可以作为Thread类的target。
    在Future接口里定义了如下几个公共方法来控制它关联的Callable任务。
    (1)、boolean cancel(boolean mayInterruptIfRunning):试图取消该Future里关联的Callable任务。
    (2)、V  get():返回Callable任务里call()方法的返回值。调用该方法将导致程序阻塞,必须等到子线程结束后才会得到返回值。
    (3)、V  get(long timeout,TimeUnit unit):返回Callable任务里call()方法的返回值。该方法让程序最多阻塞timeout和unit指定的时间,如果经过指定时间后Callable任务依然没有返回值,将会抛出TimeoutException异常。
    (4)、boolean isCancelled():如果在Callable任务正常完成前被取消,则返回true。
    (5)、boolean isDone():如果Callable任务已完成,则返回true。
    注意:Callable接口有泛型限制,Callable接口里的泛型形参类型与call()方法返回值类型相同。
    创建并启动有返回值的线程步骤如下:
    1、创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,且该call()方法没有返回值,再创建Callable实现类的实例。
    2、使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
    3、使用FutureTask对象作为Thread对象的target创建并启动新线程。
    4、调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。
     
    采用实现Runnable、Callable接口的方式创建多线程的优缺点:
    1、线程类只是实现了Runnable接口或者Callable接口,还可以继承其他类。
    2、在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现面向对象的思想。
    缺点是:编程稍稍复杂,如果需要访问当前线程,则必须使用Thread.currentThread()方法。
     
    采用继承Thread类的方式创建多线程的优缺点:
    1、缺点是,因为线程类已经继承了Thread类,所以不能再继承其他父类。
    2、优点是,编写简单,如果要访问当前线程,则无须使用Thread.currentThread()方法,直接使用this即可获得当前线程。
     
    总结:采用Runnable接口、Callable接口的方式来创建多线程。

  • 相关阅读:
    地磁室内导航定位
    毛蔚青:图片室内定位
    利用Project Tango进行室内三维建模 精度评定
    傅里叶变换详解
    第四届空间信息智能服务研讨会会议指南
    联想Phab2 Pro Tango手机测评
    Learning ROS for Robotics Programming
    柳景斌:智能手机室内定位与智能位置服务
    VR
    发送get和post请求时常用的content-type
  • 原文地址:https://www.cnblogs.com/glfcdio/p/8108099.html
Copyright © 2011-2022 走看看