Java教程

《Java多线程编程核心技术第二版》读书笔记

本文主要是介绍《Java多线程编程核心技术第二版》读书笔记,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

一、总结

这本书写的很浅,更多的是案例,ThreadLocal部分还可以,原理基本讲到了

大致总结了下面部分知识点

二、内容

在什么情况下使用多线程?

  • 阻塞
  • 依赖,如业务分为两个执行过程,当A业务阻塞的时候,B业务的执行不依赖A业务的执行结果

start()方法耗时的原因是因为执行了多个步骤

  • 通过JVM告诉操作系统创建Thread
  • 通过系统开辟内存并使用WindowsSDK中的createThread()函数创建Thread对象
  • 操作系统对Thread对象进行调度,以确定执行时机
  • Thread在操作系统内部成功执行

使用常见的命令分析线程

  • jps + jstack.exe:jps查看全部线程,然后jps -l 进程id
  • jmc.exe可视化界面
  • jvisualvm.exe可视化界面

停止一个线程

  • 使用退出标志正常退出
  • 使用stop()方法强制终止线程,同方法suspend()、remuse()都是过时的方法,使用可能发生不可意料的结果,因为过程不会释放锁
  • 使用interrupt()方法中断线程
  • yield()方法是暂停当前线程放弃cpu资源,但是放弃的时间不确定

优先级

  • 在Java中,线程的优先级1~10共10个等级
  • 线程优先级具有继承性,A线程创建B线程,他们的优先级相同

守护线程,Java中有两种线程

  • 非守护线程:即用户线程
  • 守护线程:当非守护线程不存在之后,自动销毁,典型的就是垃圾回收线程

同步关键字sychronized概述,使用javap命令反编译class文件为字节码

  • 方法加了synchronized,发现在方法前面多了ACC_SYNCHRONIZED
  • 同步代码块,使用monitorenter、monitorexit指令进行同步处理

注意

  • 加在非静态方法,对象锁锁的是当前类的Object实例对象,锁的并不是当前方法或者代码块的代码,而是第一个持有该方法的线程
  • 如果在X对象中使用了synchronized修饰非静态方法,则X对象就被当成锁
  • 可重入的,在synchronized修饰的代码块、方法内部调用本类的其他synchronized是永远可以拿到锁的
  • 加在静态方法,锁的是当前类的Class类对象,对所有的对象实例起作用

volatile三个特性

  • 可见性
  • 不保证原子性:加了volatile的变量执行i++也不是原子操作,需要配合synchronized
  • 禁止代码重排序

线程间通信

  • 执行noty()方法不会立即释放锁,执行wait()会立即释放锁,唤醒的顺序与wait的顺序一致,在生产者消费者模式不保证唤醒的是同类还是异类
  • xxx线程实例.join()方法执行,停止当前实例所在线程的执行,执行线程实例的run方法,有线程排队运行的结果
  • wait()方法释放锁,sleep()不释放锁

ThreadLocal类

  • 主要作用是将数据放到当前运行线程的成员变量Map中,本身不存储数据,作为桥梁
  • Map中的key存储的是ThreadLocal对象
  • Thread类内有一个内部内ThreadLocalMap,对应创建成员属性threadLocals,使用set的时候,会调用createMap()方法,该方法的实现在ThreadLocal类中
  • 初始调用ThreadLocal的实例对象的get()方法返回为null,可以继承ThreadLocal重写initialValue()方法设置初始值
  • ThreadLocal类不能实现值继承,创建子线程的父线程不会把设置的值传给子线程,可以使用InheritableThreadLocal体现值的继承性,它继承Thread类

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

InheriatbleThreadLocal实现值继承的原理

  • inheritableThreadLocals同threadLocals都是Thread的成员变量,开始为null
  • InheriatbleThreadLocal继承ThreadLocal但是没有方法上面无@Override
  • 调用InheriatbleThreadLocal对象的set()方法其实就是调用threadLocals的方法,因为没有重写set方法,而get()方法内部又调用的createMap()和getMap都是自己重写的方法

具体的原理就是:

  • 父线程调用InheriatbleThreadLocal实例的set()方法,就是向InheriatbleThreadLocal容器存数据
  • 进而在创建子线程的时候,子类主动引用其父线程的InheriatbleThreadLocal值

package java.lang;
import java.lang.ref.*;

/**
 * This class extends {@code ThreadLocal} to provide inheritance of values
 * from parent thread to child thread: when a child thread is created, the
 * child receives initial values for all inheritable thread-local variables
 * for which the parent has values.  Normally the child's values will be
 * identical to the parent's; however, the child's value can be made an
 * arbitrary function of the parent's by overriding the {@code childValue}
 * method in this class.
 *
 * <p>Inheritable thread-local variables are used in preference to
 * ordinary thread-local variables when the per-thread-attribute being
 * maintained in the variable (e.g., User ID, Transaction ID) must be
 * automatically transmitted to any child threads that are created.
 *
 * <p>Note: During the creation of a new {@link
 * Thread#Thread(ThreadGroup,Runnable,String,long,boolean) thread}, it is
 * possible to <i>opt out</i> of receiving initial values for inheritable
 * thread-local variables.
 *
 * @author  Josh Bloch and Doug Lea
 * @see     ThreadLocal
 * @since   1.2
 */

public class InheritableThreadLocal<T> extends ThreadLocal<T> {
    /**
     * Computes the child's initial value for this inheritable thread-local
     * variable as a function of the parent's value at the time the child
     * thread is created.  This method is called from within the parent
     * thread before the child is started.
     * <p>
     * This method merely returns its input argument, and should be overridden
     * if a different behavior is desired.
     *
     * @param parentValue the parent thread's value
     * @return the child thread's initial value
     */
    protected T childValue(T parentValue) {
        return parentValue;
    }

    /**
     * Get the map associated with a ThreadLocal.
     *
     * @param t the current thread
     */
    ThreadLocalMap getMap(Thread t) {
       return t.inheritableThreadLocals;
    }

    /**
     * Create the map associated with a ThreadLocal.
     *
     * @param t the current thread
     * @param firstValue value for the initial entry of the table.
     */
    void createMap(Thread t, T firstValue) {
        t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
    }
}

在这里插入图片描述
在这里插入图片描述

  • 子线程将父线程的table对象以赋值的方式赋值给子线程,这个过程是创建Thread对象的时候自动完成的,只要父线程的InheriatbleThreadLocal不为null
  • 父线程更新了InheriatbleThreadLocal的数据之后,子线程也不会更新,反之子线程更新也不影响父线程,但是指针指向的如一个对象的属性值,还是会变得。另外就是可以重写childValue()可以进行子线程对父线程继承的值进行加工

Lock对象的使用

  • JDK1.5新增的ReentrantLock类功能更多了,如嗅探锁定,多路分支等
  • 进程间通信需要借助Condition类的await()、signal()
这篇关于《Java多线程编程核心技术第二版》读书笔记的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!