文章目录

  • 一.用一句话讲明白进程和线程的关系(不甚严密)
  • 二.浅析进程与线程
  • 三.多线程
  • 四.Java中的线程是什么样子的
  • 五.java.lang.Thread & java.lang.Runnable
    • Thread
    • Runnable
    • 使用run()方法——线程运行体
  • 六.进程的生命周期(五状态图)
  • 七.线程的生命周期
    • Java线程的生命周期(五状态图)
    • Java线程的生命周期(七状态图)
  • 八.Java线程的主要API
  • 九.Java线程的优先级
    • 线程的优先级
    • 表示线程优先级的常量
    • 线程优先级方法
  • 十.Java线程的启动
  • 十一.Java线程的休眠
  • 十二.线程的终止
  • 十三.Object类中线程的相关高级方法
  • 十四.线程同步与synchronized
    • synchronized与互斥锁
    • private与synchronized修饰的变量
    • synchronized两种同步方式的优缺点
    • 深入分析synchronized
    • 使用synchronized实现线程安全的懒汉式单例模式
  • 十五.Java线程死锁问题
  • 十六.并发和并行的区别
  • 十七.致谢

一.用一句话讲明白进程和线程的关系(不甚严密)

操作系统可以同时执行多个任务,每个任务就是进程;一个进程可以同时执行多个任务,每个任务就是一个线程。

二.浅析进程与线程

每个正在系统上运行的程序都是一个进程。每个进程包含一到多个线程。进程也可能是整个程序或者是部分程序的动态执行。线程是一组指令的集合,或者是程序的特殊段,它可以在程序里独立执行。也可以把它理解为代码运行的上下文。所以线程基本上是轻量级的进程,它负责在单个程序里执行多任务。通常由操作系统负责多个线程的调度和执行。

线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程,但轻量进程更多指内核线程,而把用户线程称为线程。

线程是独立调度和分派的基本单位。线程可以为操作系统内核调度的内核线程,如Win32线程;由用户进程自行调度的用户线程,如Linux平台的POSIX Thread;或者由内核与用户进程,如Windows 7的线程,进行混合调度。

同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等。但同一进程中的多个线程有各自的调用栈,自己的寄存器环境,自己的线程本地存储。

线程和进程的区别在于,子进程和父进程有不同的代码和数据空间,而多个线程则共享数据空间,每个线程有自己的执行堆栈和程序计数器为其执行上下文.多线程主要是为了节约CPU时间,发挥利用,根据具体情况而定. 线程的运行中需要使用计算机的内存资源和CPU。

(这里基于Java讲多线程,所以并没有过于强调进程。其实,进程是操作系统的“主角”,对进程了解不足建议阅读《操作系统概念》(《Operating System Concepts》),从理论上全面理解进程。)

三.多线程

多线程,是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。具有这种能力的系统包括对称多处理机、多核心处理器以及芯片级多处理或同时多线程处理器。在一个程序中,这些独立运行的程序片段叫作“线程”,利用它编程的概念就叫作“多线程处理”。

简而言之,线程是程序中一个单一的顺序控制流程。在单个程序中同时运行多个线程完成不同的工作,称为多线程。

多线程编程的优点:

  • 进程之间不易共享内存,但线程之间共享内存非常容易。
  • 系统创建进程时需要为该进程重新分配系统资源,但创建线程的代价则小得多,因此使用多线程来实现多任务并发比多进程效率高。
  • Java语言内置了多线程功能的支持,而不是单纯地作为底层操作系统的调度方式,从而简化了Java的多线程编程。

四.Java中的线程是什么样子的

Java程序是通过线程执行的,线程在程序中具有独立的执行路径。当多条线程执行时,它们的路径可以不同。

每一个Java应用程序都需要有一个执行main()函数的默认主线程。应用程序也可以创建线程在后台操作时间密集型任务,以确保对用户的响应。这些封装了代码执行序列的线程对象就被成为runnable。

JVM给了每个线程分配了独立的JVM栈空间以免互相干扰。独立的栈使得线程可以追踪他们自己下一条将要执行的指令,这些指令会依线程的不同而有所区别。栈空间也为每条线程单独准备了一份方法参数、局部变量以及返回值的拷贝。

Java主要是基于java.lang.Thread类以及java.lang.Runnable接口来实现基本的线程机制的。

Thread类为底层操作系统的线程体系架构提供一套统一的接口(通常OS负责创建和管理线程)。操作系统线程和Thread对象关联(具体怎么关联关系还要看OS的设计)。

Runnable接口则为关联Thread对象的线程提供执行代码。这些代码放在Runnable的void run()方法中,这个方法虽然不接收任何参数且没有返回值,但有可能抛出异常。

五.java.lang.Thread & java.lang.Runnable

Thread


这个类里面有大量不常见的关键词:

  • volatile
  • native
  • synchronized

Runnable

package java.lang;@FunctionalInterface
public interface Runnable {public abstract void run();
}

我们去掉注释,不算空行,其实Runnable接口只有5行:

  1. 定义包名。
  2. 注解表明函数式接口。
  3. 定义接口名为Runnable。
  4. 定义抽象方法run(),返回值无。
  5. 类代码段结束。

使用run()方法——线程运行体

要将一段代码(线程体)在一个新的线程上运行,该代码应该在一个线程类的run()函数中。

  • 写一个类implements Runnable接口,就必须重写Runnable接口中的run()方法
  • 写一个类extends Thread类,就应该重写Thread类的run()方法

六.进程的生命周期(五状态图)

下图为进程的五状态图:

七.线程的生命周期

Java线程的生命周期(五状态图)

Java线程的生命周期(七状态图)


八.Java线程的主要API

方法 功能
isAlive() 判断线程是否还未被终止
getPriority() 获取线程优先级
setPriority() 设置线程优先级
Thread.sleep() 线程休眠
join() 等待调用线程运行的结束,再执行当前线程
yield() 让出资源,进入就绪队列等候

九.Java线程的优先级

线程的优先级

  • Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照线程的优先级来决定应调度哪个线程来执行
  • Java线程的优先级用1~10的整数来表示,越小则优先级越低
  • Java的优先级是高度依赖于操作系统的实现的

表示线程优先级的常量

Thread类有三个常量,表示常用的线程优先级:

  • Thread.MIN_PRIORITY //1
  • Thread.NORM_PRIORITY // 5
  • Thread.MAX_PRIORITY // 10

线程默认是NORM_PRIORITY,优先级为5,包括main()线程。

线程优先级方法

  • getPriority():确定线程的优先级
  • setPriority():设置线程的优先级

十.Java线程的启动

run()方法内是线程执行的代码段,但一定要记住:不是用run()启动线程!!!

应该用start()启动!!!

十一.Java线程的休眠

与线程休眠有关的方法有三个:

  • sleep()

    • 让线程中止一段时间的静态方法
    • Thread.sleep(long millis):暂时停止执行millis毫秒
    • 在睡眠期满的瞬间,再次调用该线程不一定会恢复它的执行,因为它很可能在等待队列中
  • join()
    • 导致当前线程等待,直到调用这个 join 方法的线程终止
    • join( )
    • join(long millis)
    • join(long millis,int nanos)
  • yield()
    • 为其他可运行的线程提供执行机会
    • 静态方法 — Thread.yield( )

十二.线程的终止

  • 自动终止:一个线程完成执行后,不能再次运行
  • 手动终止:
    • stop():已过时,基本不用
    • interrupt(): 粗暴的终止方式
    • 可通过使用一个标志指示 run() 退出,从而终止线程

十三.Object类中线程的相关高级方法

  • void wait():导致当前的线程等待,直到其他线程调用此对象的 notify()方法或 notifyAll() 方法
  • void notify():唤醒在此对象监视器上等待的单个线程
  • void notifyAll():唤醒在此对象监视器上等待的所有线程

十四.线程同步与synchronized

线程同步最简单的方法是使用synchronized关键词。

该关键词可以用于修饰变量或者方法。

  • synchronized修饰变量:

    synchronized (obj){// 需要被同步的代码
    }
    
  • synchronized修饰方法:
    public synchronized void function(){//同步方法的内容
    }
    

synchronized与互斥锁

在Java语言中,引入了对象互斥锁的概念,来保证共享数据操作的完整性

  • 每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象
  • 关键字synchronized来与对象的互斥锁联系。当某个对象用synchronized修饰时,表明该对象在任一时刻只能由一个线程访问
  • 同步的局限性:导致程序的执行效率要降低
  • 同步方法(非静态的)的锁为this
  • 同步方法(静态的)的锁为当前类本身

private与synchronized修饰的变量

受到synchronized保护的程序代码块和方法中,要访问的对象属性必须设定为private,因为如果不设定为private,那么就可以用不同的方式来访问它,这样就达不到保护的效果了。

synchronized两种同步方式的优缺点

  • synchronized方法
    优点:

    • 可以显示的知道哪些方法是被synchronized关键字保护的

    缺点:

    • 方法中有些内容是不需要同步的,如果该方法执行会花很长时间,那么其他人就要花较多时间等待锁被归还
    • 只能取得自己对象的锁,有时候程序设计的需求,可能会需要取得其他对象的锁
  • synchronized代码块
    优点:

    • 可以针对某段程序代码同步,不需要浪费时间在别的程序代码上
    • 可以取得不同对象的锁

    缺点:

    • 无法显示的得知哪些方法是被synchronized关键字保护的

深入分析synchronized

synchronized关键词实际上使用管程ADT实现,原先效率很低,Java的几个重要版本中经历不断优化已经好很多了,但还是慢。

个人觉得大家可以这么去理解synchronized:所谓多线程程序,其实是巧妙地利用了多核系统的并发并行,并发与并行对其很重要。但是,synchronized与所谓管程(操作系统的概念),正是对这里开刀,它不给你控制的机会,直接保证临界区(操作系统的概念)代码段的执行从并发、并行到串行,一次只能走一条线程。它相当于一种悲观锁,直接粗暴地化并发、并行为串行,保证了并发程序的同步与共享数据一致性。

使用synchronized实现线程安全的懒汉式单例模式

public class Singleton {private static Singleton instance = null;private Singleton() {}  public static Singleton getInstance() {   if(instance == null) {    synchronized(Singleton.class) {     if(instance == null) {      instance = new Singleton();     } } }   return instance;  }
}

测试类:

public class SingletonTest {  public static void main(String[] args) {   Singleton s1 = Singleton.getInstance();   Singleton s2 = Singleton.getInstance();   System.out.println(s1==s2);  }
}

十五.Java线程死锁问题

(不规范解释) 死锁:两个线程,彼此在等待对方释放其持有的锁,而陷入无线等待。

锁的归还几种方式:

  • 基本上执行完同步的程序代码后,锁就会自动归还
  • 用break语句跳出同步的语句块,不过这对于写在方法声明的 synchronized没有作用
  • 遇到return语句
  • 遇到异常

十六.并发和并行的区别

荐读:《并发和并行的区别》

十七.致谢

  • 感谢@码农云帆哥的指正,已改

【Java】撩开Java线程的“神秘面纱”相关推荐

  1. 揭开Java 泛型类型擦除神秘面纱

    转载自   揭开Java 泛型类型擦除神秘面纱 泛型,一个孤独的守门者. 大家可能会有疑问,我为什么叫做泛型是一个守门者.这其实是我个人的看法而已,我的意思是说泛型没有其看起来那么深不可测,它并不神秘 ...

  2. 万字图文 | 学会Java中的线程池,这一篇也许就够了!

    来源:一枝花算不算浪漫 线程池原理思维导图.png 前言 Java中的线程池已经不是什么神秘的技术了,相信在看的读者在项目中也都有使用过.关于线程池的文章也是数不胜数,我们站在巨人的肩膀上来再次梳理一 ...

  3. 面试官:Java如何绑定线程到指定CPU上执行?

    不知道你是啥感觉,但是我第一次看到这个问题的时候,我是懵逼的. 而且它还是一个面试题. 我懵逼倒不是因为我不知道答案,而是恰好我之前在非常机缘巧合的情况下知道了答案. 我感觉非常的冷门,作为一个考察候 ...

  4. Java常用四大线程池用法以及ThreadPoolExecutor详解

    2019独角兽企业重金招聘Python工程师标准>>> 为什么用线程池? 1.创建/销毁线程伴随着系统开销,过于频繁的创建/销毁线程,会很大程度上影响处-理效率 2.线程并发数量过多 ...

  5. Java多线程之线程池的使用示例

    2019独角兽企业重金招聘Python工程师标准>>> 第一种:创建一个定长的线程池,控制线程最大并发数,超出的会在队列中等待. TestThreadPool.java import ...

  6. Java:定时启动线程

    参考:http://zhangjunhd.blog.51cto.com/113473/74646     http://www.cnblogs.com/jobs/archive/2007/04/27/ ...

  7. 【Java 集合】Java 集合的线程安全性 ( 加锁同步 | java.utils 集合 | 集合属性 | java.util.concurrent 集合 | CopyOnWrite 机制 )

    文章目录 I . Java 集合的线程安全概念 ( 加锁同步 ) II . 线程不安全集合 ( 没有并发需求 推荐使用 ) III . 集合属性说明 IV . 早期的线程安全集合 ( 不推荐使用 ) ...

  8. Java并发编程——线程池的使用

    在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统 ...

  9. java中的线程安全是什么?

    java中的线程安全是什么: 就是线程同步的意思,就是当一个程序对一个线程安全的方法或者语句进行访问的时候,其他的不能再对他进行操作了,必须等到这次访问结束以后才能对这个线程安全的方法进行访问. 什么 ...

最新文章

  1. java 执行javascript_说说如何在 Java 中执行 JavaScript 脚本
  2. [Python]小甲鱼Python视频第003课(插曲之变量和字符串)课后题及参考解答
  3. sklearn 笔记:make_blobs 生成聚类数据
  4. 集大通100%任务完成度签到
  5. cordova项目适配iPhoneX
  6. java调试案例_Spring-boot的debug调试代码实例
  7. [react] 你最不喜欢React的哪一个特性(说一个就好)?
  8. 程序员可以只关心技术么?
  9. centos7永久修改ip地址
  10. python微软产品一般都一个25位的序列号_Python易错点6
  11. NSTimer(2)
  12. EXCEL VBA编程入门一
  13. AppStore 预览图制作
  14. 贪心算法 Y 美味酸奶
  15. 1.javascript 自动定时刷新网页脚本
  16. 软件测试预演环境,什么是软件测试用例预演 有何优点?[3]
  17. ARP协议格式和实例分析
  18. iOS 自定义播放器
  19. 我的Python心路历程 第十期 (10.10 股票实战可视化历史趋势)
  20. svg中marker元素的理解

热门文章

  1. 企业案例(二):增量恢复案例
  2. poi导出Excel(分行单元格颜色设置,字体设置,合并单元格,插入图片)
  3. 真机iOS SDK升级后xcode不能进行真机调试 怎么办
  4. 深入沟通的重要性——《大道至简》第四章读后感
  5. 2013年11月19日
  6. java多线程编程基础
  7. SQL - 18.触发器
  8. 微信开发--自定义菜单
  9. 蓝桥杯第六届省赛JAVA真题----生命之树
  10. centos下离线安装mysql