• Java 多线程


    1、多线程简介

    1.1线程和进程

    Java 给多线程编程提供了内置的支持。 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。多线程是多任务的一种特别的形式,但多线程使用了更小的资源开销。


    这里定义和线程相关的另一个术语 - 进程:一个进程包括由操作系统分配的内存空间,包含一个或多个线程。一个线程不能独立的存在,它必须是进程的一部分。一个进程一直运行,直到所有的非守护线程都结束运行后才能结束。

    多线程能满足程序员编写高效率的程序来达到充分利用 CPU 的目的。**
    (进程——自我理解——一个正在执行的程序,称之为一个进程。)
    (线程——本身没有资源,所有线程共享进程的资源。)

    同一时间,一个CPU(一个核),只能处理一个线程!!!

    你在任务管理器中查看到的几千个线程,并不不是在同一时间执行的。

    1.4 线程的交互

    交互的方式 包括 :  互斥  、同步。
    争用条件

    互斥

    同步

    1.5 Java对线程的支持

    1.6 如何正确地停止一个线程?

    不正确的线程停止方法

    stop()调用后,会不知道,线程执行到了哪里,甚至,还没有执行完,就被突然停止了。会造成很多问题。比如,如果此处涉及到事务,那么,事务,可能就不会被提交或者出现异常后,不会被回滚。

    不正确的停止线程的方法2:

    注意:此时,线程的中断状态,就会被清除,再次调用interrupted()方法,就会返回false。

    正确停止线程的方法——使用退出标志

    1.7 Daemon 守护线程和 用户线程

    daemon线程解释: 当线程只剩下守护线程的话,jvm会退出。但是如果还有其他的任意一个用户线程还在,jvm就不会退出。main线程是用户线程。

    守护线程和主线程有着同样的生命周期,主线程不存在,子线程也就不存在了
    非守护线程和主线程无关,主线程关闭,子线程继续执行

    1.8 可重入锁

    A:概念
    最大的作用是可以多次获取该锁,而避免死锁。

    电影院售票示例

    B:可重入所实现原理

    精品文章1

    C:可重入锁应用场景

    D:注意事项

    1. lock.lock() ,不要放在try语句里面,防止获取锁失败,直接释放锁。
    2. 获取锁的次数和释放锁的次数要一致!

    E:使用方式
    1. 一般在成员变量位置,定义一个锁(对象锁?)。在方法(临界区)进行上锁。finally中一定要unlock.

    1.9 多线程的理解

    • (1) 程序可以同时由多个线程执行多个方法(代码)

    3、线程池

    3.1 线程池的创建

    • 阿里巴巴开发规范
      线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。 说明:Executors返回的线程池对象的弊端如下:
      1)FixedThreadPool和SingleThreadPool:
        允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM。
      2)CachedThreadPool:
        允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM。

    Positive example 1:

    //org.apache.commons.lang3.concurrent.BasicThreadFactory
        ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1,
            new BasicThreadFactory.Builder().namingPattern("example-schedule-pool-%d").daemon(true).build());
    

    Positive example 2:

    ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
            .setNameFormat("demo-pool-%d").build();
    
        //Common Thread Pool
        ExecutorService pool = new ThreadPoolExecutor(5, 200,
            0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
    
        pool.execute(()-> System.out.println(Thread.currentThread().getName()));
        pool.shutdown();//gracefully shutdown
    

    Junit 与 Java多线程

    暂时,无法正确测试

    总结

    1、线程创建后,调用线程的start()方法开启一个线程,线程开启后,每个线程会执行线程的核心业务方法run()方法 。并且只会执行一次。

    2、创建线程类的三种方式:

    继承Thread  类

    实现 Runnable 接口

    实现Callable 或者Futre接口

    5、并发工具类

    A:CountDownLatch
    参考源码中的文档查看:

    B:FutureTask 配合Callable接口使用

    6、Java原子类以及实现原理

    精品文章1
    精品文章2

    7、悲观锁和乐观锁

    悲观锁: Synchronized

    乐观锁:CAS 机制

    8、 线程编写经验

    • (1)run方法中,会写一个while 无限循环,在特定条件下使用return结束任务。
    • (2)在构造器中启动线程将会产生问题,因为,另一个任务可能会在构造器结束之前,开始执行,这意味着,该线程可以访问不稳定状态的对象。
    • (3)使用内部类隐藏线程代码

    9、 线程中异常的处理

    • (1) 异常不能够跨线程传播,必须在任务方法中进行捕获处理。

    二、多线程编程思想

    2.1 多线程的使用场景?

    • 1. 一次请求很久才能响应

      当主线程在处理一件事情时,发现在处理过程中,会消耗很长时间。主线程可能会等待后续的响应。此时,可以使用多条子线程来处理后续的任务。
      示例:主线程一次性查询出 线程数量 * 1000 条数据从数据库。然后使用线程池,提交一定数量的线程来处理这些数据。

    三、Java并发编程的艺术

    3.1 上下文切换

    Linux 如何测试上下文切换消耗?

    A:Java性能调优工具

    • jstack
      Jstack是Jdk自带的线程跟踪工具,用于打印指定Java进程的线程堆栈信息。

    配合使用Linux文本分析命令分析
    grep | awk | sort | uniq -c

    四、多线程面试题

    4.1 wait 和sleep 方法的区别 ?

    wati 和sleep 方法的区别?

    喜欢出发、喜欢离开、喜欢不一样的事物。——May
  • 相关阅读:
    WPF数据绑定机制是如何实现
    C#自定义特性的使用
    MVVMLight学习笔记(一)---MVVMLight概述
    C# Autofac学习笔记
    EFCodeFirst快速搭建入门
    SQL having与where用法区别
    EventWaitHandle 类
    C# EF 使用 (CodeFirst模式)
    wmi 远程启动程序
    Centos 7 的一些 基础知识
  • 原文地址:https://www.cnblogs.com/I-Say/p/14479299.html
Copyright © 2020-2023  润新知