先拜拜大神

Doug Lea(道格.利)

java.util.concurrent在并发编程中使用的工具包

为什么学习并用好多线程极其重要

硬件方面

摩尔定律失效

摩尔定律:它是由英特尔创始人之一Gordon Moore(戈登.摩尔)提出来的。其内容为:

当价格不变时,集成电路上可容纳的元器件的数目约每隔18-24个月便会增加一倍,性能也将提升一倍。换言之,每一美元所能买到的电脑性能,将每隔18-24个月翻一倍以上。这一定律揭示了信息技术进步的速度。

可是从2003年开始CPU主频已经不再翻倍,而是采用多核而不是更快的主频摩尔定律失效了。在主频不再提高且核数在不断增加的情况下,要想让程序更快就要用到并行或并发编程

软件方面

  • 充分利用多核处理器
  • 提高程序性能,高并发系统
  • 提高程序吞吐量,异步+回调等生产需求

弊端及问题

  • 线程安全性问题:如i++、集合类安全问题
  • 线程锁问题
  • 线程性能问题
从start一个线程说起

java线程理解以及openjdk中的实现

private native void start0();

java语言本身底层就是C++语言

OpenJDK源码网址

http://openjdk.java.net/

可以下载源码到本地观看openjdk\hotspot\src\share\vm\runtime

更加底层的C++源码解读

1、openjdk8\jdk\src\share\native\java\lang

thread.c

java线程是通过start的方法启动执行的,主要内容在native方法start()中,openjdk的写JNI一般是一一对应的,Thread.java对应的就是Thread.c,start0其实就是JVM_StartThread。此时查看源代码可以看到在jvm.h中找到了声明,jvm.cpp中有实现。

2、openjdk8\hotspot\src\share\vm\prims

jvm.cpp

3、openjdk8\hotspot\src\share\vm\runtime

thread.cpp

java多线程相关概念

1把锁

synchronized

2个并

并发(concurrent):是在同一实体上的多个事件;是在一台处理器上“同时”处理多个任务;同一时刻,其实是只有一个事件在发生。

并行(parallel):是在不同实体上的多个事件;是在多台处理器上同时处理多个任务;同一时刻,大家真的都在做事情,你做你的,我做我的,但是我们都在做。

并发VS并行

3个程

进程:简单的说,在系统中运行的一个应用程序就是一个进程,每一个进程都有它自己的内存空间和系统资源。

线程:也被成为轻量级进程,在同一个进程内会有1个或多个线程,是大多数操作系统进行时序调度的基本单元。

管程

Monitor(监视器),也就是我们平时所说的锁

Monitor其实是一种同步机制,它的义务是保证(同一时间)只有一个线程可以访问被保护的数据和代码。

JVM中同步是基于进入和退出监视器对象(Monitor管程对象)来实现的,每个对象实例都会有一个Monitor对象:

Object o = new Object();

new Thread(() -> {

        synchronized(o) {

        }

}, "t1").start();

Monitor对象会和java对象一同创建并销毁,它底层是由C++语言来实现的。

JVM第3版

6.4.10同步指令

Java虚拟机可以支持方法级的同步和方法内部一段指令序列的同步,这两种同步结构都是使用管程(Monitor,更常见的是直接将它称为“锁”)来实现的。

方法级的同步是隐式的,无须通过字节码指令来控制,它实现在方法调用和返回操作之中。虚拟机可以从方法常量池中的方法表结构中的ACC_SYNCHRONIZED访问标志得知一个方法是否被声明为同步方法。当方法调用时,调用指令将会检查方法的ACC_SYNCHRONIZED访问标志是否被设置,如果设置了,执行线程就要求先成功持有管程,然后才能执行方法,最后当方法完成(无论是正常完成还是非正常完成)时释放管程。在方法执行期间,执行线程持有了管程,其他任何线程都无法再获取到同一个管程。如果一个同步方法执行期间抛出了异常,并且在方法内部无法处理此异常,那这个同步方法所持有的管程将在异常抛到同步方法边界之外时自动释放。

同步一段指令集序列通常是由java语言中的synchronized语句块来表示的,java虚拟机的指令集中有monitorenter和monitorexit两条指令来支持synchronized关键字的语义,正确实现synchronized关键字需要javac编译器与java虚拟机两者共同协作支持。

用户线程和守护线程

java线程分为用户线程和守护线程

一般情况下不做特别说明配置,默认都是用户线程

用户线程(User Thread):是系统的工作线程,它会完成这个程序需要完成的业务操作。

守护线程(Daemon Thread)是一种特殊的线程为其他线程服务的,在后台默默地完成一些系统性的服务,比如垃圾回收线程就是最典型的例子;守护线程作为一个服务线程,没有服务对象就没有必要继续运行了,如果用户线程全部结束了,意味着程序需要完成的业务操作已经结束了,系统可以退出了。所以假如当系统只剩下守护线程的时候,java虚拟机会自动退出。

线程的daemon属性

源码解读

true表示是守护线程

false表示是用户线程

code演示

package com.lzx.juc.base;

import java.util.concurrent.*;

/**
 * @author admin
 */
public class DaemonDemo {
    
    //一切方法运行的入口
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "\t 开始运行, " +
                    (Thread.currentThread().isDaemon() ? "守护线程" : "用户线程"));
            while (true) {

            }
        }, "t1");
        
        t1.start();
        t1.setDaemon(true);

        //暂停几秒钟线程
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(Thread.currentThread().getName() + "\t ----end 主线程");
    }
    
}

小总结

如果用户线程全部结束意味着程序需要完成的业务操作已经结束了,守护线程随着JVM一同结束工作。

setDaemon(true)方法必须在start()之前设置,否则报IllegalThreadStateException异常:为什么?

你不能把正在运行的常规线程设置为守护线程。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐