Java并发编程的艺术-----第四章读书笔记

版权声明:欢迎转载大宇的博客,转载请注明出处: https://blog.csdn.net/yanluandai1985/article/details/82796054

4.1.2

        为什么要使用多线程?

        一个线程同一时刻只能运行在一个处理器核心上。如果程序使用多线程,那么程序就会被分配到多个处理器核心上,这样就会显著减少程序的处理时间,并且随着更多处理器核心的加入,程序的执行会变得更有效率。P84

        使用多线程的程序:耗时少,效率高。    

4.1.3

        线程会得到OS分配的若干时间片,当线程的时间片用完了就会发生线程调度,并等待着下次OS分配

4.1.4

       如何查看线程的状态?

       在终端输入 jps  ,我们运行的Java类的名字是ThreadState。所以JPS可以看到我的Java代码的进程ID为3068,

       

       再通过 jstack 3068 查看进程的中的所有线程信息。

       如下图可以发现,线程名为"BolckedThreadB"的线程的状态为 TIMED_WAITING ,说明此线程调用了 Thread.sleep()方法。

      

       下图也显示了,名为BlockedThreadA的线程的状态,现在是BLOCKED状态。BolckedThreadA这个线程与BolckedThreadB这个线程共享的是同一把锁,而BolckedThreadB线程调用了Thread.sleep()方法不会释放同步锁。所以这个BolckedThreadA线程就没能够获取到同步锁,所以只能进入同步队列中,进入阻塞状态 BLOCKED。

      

4.1.5

       join()方法内部使用的wait()方法,因此,调用A.join()方法的当前线程,注意是当前线程,将会进入阻塞状态WAITING,并同时释放同步锁。当前线程等待线程A执行完毕后继续执行。

       线程对象调用 Thread.setDaemon(true)设置为守护线程。

       Java虚拟机退出时,守护线程中的finally块不一定会执行

       因为系统中一旦没有非守护线称的时候,守护线程将会立即关闭

4.2.3

       中断可以理解为线程的一个标识位属性。P92

       我一般将其理解为中断标志位。如果这个线程调用 Thread.isInterrupted()方法,返回的是false,说明就是未中断的。

       方法在抛出InterruptedException之前,Java虚拟机会先将程序的中断标志位清除。P92

       终于找到为什么每次进入异常处理语句后,此线程的中断标志位就变成false了。

       在补充一句:哪个线程直接调用了 interrupt()方法,哪个线程的中断状态位立即置为true。而很多方法,比如Thread.sleep()方法,对中断状态位敏感,一旦侦测到中断状态位为true,立即中断线程,进入异常处理语句。

4.2.4

       为什么 stop()、suspend()方法被废弃。因为这两个方法一个立即释放同步锁导致脏读,资源没清理),一个不释放同步锁导致死锁)。

4.2.5

        如何安全的停止线程? 目标:终止线程的时候有机会去清理资源,而不是武断的停止线程。

        方法一就是采用中断状态位了。调用interrupt()方法即可。任务循环判断 线程的中断状态位  isInterrupted()。

        方法二就是为线程定义一个boolean类型的标记flag,提供一个方法改变这个flag的值。任务循环判断这个flag即可。

4.3.1

        关键字synchronized表示:同一时刻,只能有一个线程处于临界区中。它能保证变量的可见性与排他性。P96

        可见性分析:在释放锁的时候,将线程私有变量刷新到主存。获取锁的时候,将私有内存中变量的值废弃,重新从主存中获取最新变量的值

        排他性分析:在进入同步代码之前,使用监视器进入指令。在方法退出或者异常出,使用监视器退出指令。保证临界区内中有一个线程。

        synchronized的原理可以这么理解:同一时刻,只能有一个线程能够获取到synchronized所保护的同步锁的监视器对象。

4.3.3

       消费者生产者模式经典范式。

      (1)获取对象的锁

      (2)如果条件不满足,调用wait()方法,被通知后仍然需要检查条件。

      (3)条件满足,执行业务逻辑。

            synchronized (lock){
                while(条件不满足){
                    lock.wait();
                }
                doSomething();   //执行业务逻辑;
                lock.notifyAll();//唤醒其它线程
            }

4.3.6

        作者提供了一个非常使用的性能分析工具,采用ThreadLocal实现,可以应到到AOP中。我的想法是在前置通知中,调用开始记录时间的方法,将当前时间记录到ThreadLocal中。在后置返回通知或者后置异常通知里面调用另外一个方法,计算出本次方法的耗时。

        参考:https://github.com/hairdryre/MyJavaLife/blob/master/src/main/java/cn/jay/aop/TimeReporter.java

4.4.1

       等待超时经典代码

       

    /**
     * 在指定时间之内期望获取一个结果
     * 若没有获取到结果,那么返回默认的结果
     *
     * 时间轴, remain = future - now;
     * 
     * --------start----------now----------future
     *
     * @param millis 指定时间
     * @return 期望得到的结果,若在时间之内获取失败,返回默认的结果
     * @throws InterruptedException 中断异常
     */
    public synchronized Object get(Long millis) throws InterruptedException {
        //截止时间点
        long future = System.currentTimeMillis() + millis;
        //剩余时间
        long remain = millis;
        //当结果为空或者剩余时间还有的时候,执行下面的方法
        while (result == null && remain > 0) {
            //继续等待其它线程唤醒。
            //这个方法时间到了以后,会自动唤醒
            wait(remain);
            //如果是其它线程叫醒的,看看剩余时间还剩多久
            remain = future - System.currentTimeMillis();
        }
        return result;
    }

猜你喜欢

转载自blog.csdn.net/yanluandai1985/article/details/82796054