zoukankan      html  css  js  c++  java
  • 《Java多线程编程核心技术》笔记

    同步自https://gitee.com/Corvey/note

    第一章 Java多线程技能

    • 使用多线程时,代码的运行结果于代码执行顺序或调用顺序无关。
    • interrupted()Thread的静态方法,用于测试当前线程(即执行该方法的线程)是否已经是中断状态,执行后将清除中断状态的标志。
    • isInterrupted()为非静态方法,用于测试线程对象是否已经是中断状态,但不清楚状态标志。
    • 线程在sleep状态下interrupt的话,会在run()中抛出InterruptedException,并且清除中断状态标志。
    • 线程在interruptsleep的话,会在run()中抛出InterruptedException,并且清除中断状态标志。
    • yield()方法的作用是放弃当前的CPU资源,将它让给其他的任务去占用CPU执行时间。
    • 线程的优先级是继承的。
    • 当最后一个非守护线程结束时,守护线程才随着JVM一同结束工作。

    第二章 对象及变量的并发访问

    • synchronized声明方法时,获得的是对象锁,即相当于synchronized(this)
    • synchronized(this)没有获得该对象的成员实例变量的锁,因此调用成员变量时不一定同步。
    • synchronized(string)时要注意常量池带来的问题
    • synchronized(obj)语句块中,若obj对象发生改变,则其他线程可以进入synchronized语句块。
    • volatile要求线程每次都要从共享内存中读写变量,而不是在线程的工作内存中,因此保证了变量的可见性,但并不保证原子性,因此一般只能用于保证读取的时候数据必然是最新的。
    • synchronized可以用于线程间的互斥,还可以确保变量在内存的可见性(关于其保证可见性还需细看

    第三章 线程间通信

    • wait()方法是使当前执行代码的线程进行等待,将当前线程置入“预执行队列”,并且在wait()所在的代码行出停止执行,知道接到通知或被中断为止。在调用wait()之前,线程必须获得该对象的对象级别锁,即只能在同步方法或同步块中调用wait()方法。
    • notify()也要在同步方法或同步块中调用。执行notify()方法后,当前线程不会马上释放该锁对象锁,要等到执行notify()方法的线程将程序执行完,也就是退出synchronized代码块后。
    • P142配合第七章P280一起看
    • wait()状态下的线程被interrupt的话会报InterruptedException
    • wait(long)方法的功能是超过这个时间限制后自动唤醒。
    • join()方法的作用是使父线程等待子线程执行完毕后再执行,本质上是通过wait方法来阻塞父线程。(需要注意的是join只调用了wait,却没有对应的notify,因为在Threadstart方法中做了相应的处理,所以当join线程执行完成后会自动唤醒主线程继续往下执行)
    • join(long)方法的作用同样是使父线程等待子线程执行完毕后再执行,但如果等待时间超出指定时间则父线程继续执行。需要注意的是,由于join本质上是通过wait来阻塞父线程的,所以wait以后如果子线程长期霸占着锁不释放或者没抢到锁的话,即使超出指定时间也无法使父线程继续往下执行。 例如如下代码:
    class MyThread extends Thread {
        
        private synchronized void work() {
            try {
                System.out.println("work begin!");
                Thread.sleep(5000);
                System.out.println("work end!");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        
        @Override
        public void run() {
            try {
                Thread.sleep(1000); // 确保join方法先运行
                work();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public class Test {
        
        public static void main(String[] args) {
            MyThread t = new MyThread();
            t.start();
            try {
                System.out.println("join begin!");
                t.join(2000);
                System.out.println("join end!");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    程序输出结果为:
    join begin!
    work begin!
    work end!
    join end!
    
    • ThreadLocal类可以通过get/set存取每个线程的私有数据。通过重写initialValue方法设置get的默认值。
    • InheritableThreadLocal类可以在子线程中取得父线程继承下来的值。但子线程必须在父线程set数据后创建(注意是new而不是start)才能够继承;若要继承默认值的话,则必须等父类执行过get以后方可。子线程在创建后就会立刻继承父线程的数据,以后即使父线程修改了数据,子线程的数据还是旧的,除非传递的是可变对象。但若传递的是可变对象,则子线程修改对象后又会影响父线程的。

    第四章 Lock的使用

    • ReentrantLock类默认使用非公平锁(公平锁与非公平锁还需细看
    • locksynchronized的区别和使用还需细看
    • ReentrantReadWriteLock类为读写锁,它有两个锁,一个是读操作相关的锁,也成为共享锁;一个是写操作相关的锁,也叫排他锁。读读不互斥,读写互斥,写写互斥。

    第五章 定时器 Timer

    • Timer类主要负责计划任务,也就是在指定的时间开始执行某一个任务。默认情况下不是守护线程。通过schedule(TimerTask taks, Date firstTime)方法计划任务。若计划时间早于当前时间,则立即执行。
    • TimerTask是以队列的方式一个个地被顺序执行,因此执行的时间有可能和预期的时间不一致。因为前面的任务有可能消耗的时间较长,则后面的任务运行的时间也会被延误。被延误的任务在上一个任务完成后立即执行。
    • schedule(TimeTask task, Date firstTime, long period)方法的作用是在指定的日期之后,按指定的时间间隔周期性地无限循环执行某一任务。
    • scheduleAtFixedRateschedule延时区别没看懂?(回头细看
    • scheduleAtFixedRate若计划时间早于当前时间,会把这个时间段之间应做的任务“补充性”执行回来。

    第六章 单例模式与多线程

    第七章 拾遗增补

    • 线程有六种状态:
      • new,线程实例化后还从未执行start()方法
      • runnable,线程进入可运行状态(ready, running
      • blocked,等待锁
      • waiting,执行了wait()
      • timed_wating,线程执行了sleep()方法,呈等待状态,等待时间到达,继续向下运行
      • terminated,线程被销毁时的状态
    • 线程组的作用是,可以批量的管理线程或线程组对象,有效地对线程或线程组对象进行组织。
    • SimpleDateFormat不是线程安全的。
    • 线程的异常处理(有空再总结
  • 相关阅读:
    HashTable源码浅析(基于jdk1.8.0_231)
    LinkedHashMap源码浅析(基于jdk1.8.0_231)
    SortedSet接口源码浅析(基于jdk1.8.0_231)
    NavigableSet接口源码浅析(基于jdk1.8.0_231)
    TreeSet源码浅析(基于jdk1.8.0_231)
    TreeMap源码浅析(基于jdk1.8.0_231)
    Map接口源码解析(基于jdk1.8.0_231)
    Arrays工具类源码详解(基于jdk1.8.0_231)
    Collections源码详解(基于jdk1.8.0_231)
    BitSet源码详解 (基于jdk1.8.0.231)
  • 原文地址:https://www.cnblogs.com/corvey/p/8478785.html
Copyright © 2011-2022 走看看