第一章

1. isInterrupted()和interrupt()的区别

    public boolean isInterrupted() {return isInterrupted(false);}public static boolean interrupted() {return currentThread().isInterrupted(true);}/*** Tests if some Thread has been interrupted.  The interrupted state* is reset or not based on the value of ClearInterrupted that is* passed.*/private native boolean isInterrupted(boolean ClearInterrupted);

interrupted() 判断当前线程是否有中断标记,并清除中断标记。(jdk的命名也可读性也不好)

2. Thread.yield()方法

使当前线程从执行状态(运行状态)变为可执行态(就绪状态)。

 yield()的作用是放弃当前的cpu资源,将它让给其他的任务去占用cpu执行时间,但放弃的时间不确定,有可能刚刚放弃马上就获得了时间片。

3. 线程的优先级setPriority(int newPriority)

优先级高的分配的CPU资源会多点

4. 守护线程

5. 停止线程

可以用interrupt()和renturn结合使用

 



第二章

1.synchronized 同步语句

synchronized可以重入不可以继承

synchronized同步方法 和 synchronized(this)  用this对象作为“对象监视器”来实现同步功能。

static synchronized同步方法 和 synchronized(class)  用class类作为“对象监视器”来实现同步功能。

当我们用synchronized(**)来同步时,要注意避免用字符串来作为“对象监视器”(详情见102页)

2.volatile

volatile修饰变量,保证在多线程中变量的可见性(这句话可以理解为在一个方法里面每次去取volatile修饰的变量时都是在主内存去取而不是在私有栈去取)

下面2个图,一个是非volatile修饰,一个是有volatile修饰(很好理解吧)

下面的代码我觉得是最能解释volatile的可见性。

isRunning初始化为true

如果isRunning没有被volatile修饰,当另一个线程修改isRunning为false时,下图还一直循环(因为isRunning取的还是方法栈里面的变量值)

如果isRunning被volatile修饰,当另一个线程修改isRunning为false时,下图会打印“线程被停止了!”(因为isRunning取的还是主内存的值)

但是要记住,volatile不能保证同步,意思是不能保证原子性。



 第三章(线程间通信)

1.线程是独立的,如果让多个线程之间有联系可以用wait()和notify()来通信,

当线程要用wait()和notify(),必须要先获取对象锁,才能调用对象的await()和notify()方法。否则会出现java.lang.IllegalMonitorStateException异常。

2.当一个线程执行wait()之后,线程会停止运行,只能等待其他线程去notify().  (这个不是绝对的,见下面解释)

当另一个线程执行notify()时,当前线程并不会马上释放锁,只是随机挑选出其中一个wait()的线程,对其发送notify通知,等notify线程执行完同步方法后释放锁。

await状态的线程才能获得锁去执行代码。

3.当线程呈wati()状态时,调用线程的interrupt()方法时会出现interruptedException异常

4.带有参数的awati(long)方法,指如果在long时间内没有被其他线程notify唤醒时,会自己自动唤醒。

5.wait()方法只能由其他线程的notify去唤醒吗,NO!

那在什么情况下wait()方法会被唤醒呢,当调用wait()的对象是Thread时,如果这个线程对象在wait之前isAlive是true的时候,wait()会阻塞,

如果阻塞期间这个线程对象isAlive变为false的时候,wait()会别唤醒。看看下面代码。

当把Thread.sleep(2000);注释代码打开的时候,wait()会被唤醒。

public class MainThread
{public static void main(String[] args) throws InterruptedException{SubThread sub = new SubThread();System.out.println("MainThread----子线程状态=" +sub.getState() + "    isAlive=" + sub.isAlive());sub.start();Thread.sleep(1000);synchronized(sub){try{System.out.println("MainThread----子线程状态=" +sub.getState() + "   isAlive=" + sub.isAlive());sub.wait();System.out.println("MainThread----子线程状态=" +sub.getState() + "   isAlive=" + sub.isAlive());System.out.println("MainThread----执行结束");}catch(InterruptedException e){System.out.println("e" + e);}}  }public static class SubThread extends Thread  {  @Overridepublic void run()  {try {System.out.println("SubThread------开始  状态" +getState() + "        isAlive=" + isAlive());
//                Thread.sleep(2000);System.out.println("SubThread--------结束");} catch (Exception ex) {}}  }
}  

6. 线程的join方法就是上面的原理,(注意:join是线程的方法,wait和notify是Object的方法)

join方法:使所属的线程对象X正常执行run方法,而是当前线程Z进行无限期的阻塞,等待线程X执行完run方法销毁后再执行Z以后的代码。

在join过程中,如果当前线程Z被中断,则Z线程出现异常。

join和sleep的区别:因为join的原理是通过先锁住线程后调用wait方法实现的,所以它释放了线程的锁,而sleep不会释放锁

如下图,b.join的时候通过wait就释放了监听对象b。



第四章(ReentrantLock)

1.要实现同步除了可以用synchronized外还可以用RenntrantLock去实现;

用法就是lock.lock()和lock.unlock(); 其实最底层实现就是通过LockSupport的pack()和unpark(Thread)方法。

(知识点:当一个A线程park阻塞时,别的线程B除了可以通过unpark(A)去唤醒A,而且可以通过调用A.interrupt()去唤醒A并且不会出现InterruptedException异常)

2.RenntrantLock类里通过组合AbstractQueuedSynchronizer(AQS)去实现同步。

RenntrantLock类里有2个AQS(公平和不公平)可提供使用,通过构造器去决定使用那个具体的AQS,默认是不公平的。

2个AQS区别就是

公平AQS去lock时要判断队列里面是否有等待的线程,如果有的话就加入到队列最后,

非公平AQS去lock的时候不用判断队列里是否有线程等待,直接去竞争。如果失败了就加入到队列中去以后就是公平了。

下面是2个AQS分别获取lock的过程;

FairSync.lock()

    final void lock() {acquire(1);}public final void acquire(int arg) {//tryAcquire尝试获取锁,如果失败就addWaiter添加到线程队列,//acquireQueued会再次去获取锁,如果失败会通过LockSupport.park阻塞 等待队列前一个线程通过unpark去唤醒它//selfInterrupt的作用是(以后再说)if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();}

protected final boolean tryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {if (!hasQueuedPredecessors() &&compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}else if (current == getExclusiveOwnerThread()) {int nextc = c + acquires;if (nextc < 0)throw new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}}

NonfairSync.lock()

        final void lock() {if (compareAndSetState(0, 1))setExclusiveOwnerThread(Thread.currentThread());elseacquire(1);}/*** 其中非公平锁acquire过程中就tryAcquire跟公平锁不一样* 就是上面去掉黄色代码*/

详情细节可以参考http://www.cnblogs.com/skywang12345/p/3496147.html

http://www.cnblogs.com/waterystone/p/4920797.html

3.AQS原理简单描述

AQS有个Node节点类,有头有尾形成链表结构wait queue

那这个链表里面的数据是什么呢,就是当线程去通过lock.lock()时没有获取到锁时,把这个没有获取到锁的线程加入到链表尾部。

初始化的时候有4个线程0,1,2,3 当第一个线程0获取到锁。 链表结构组成是    (head)new node()-->等待线程1-->等待线程2-->(tail)等待线程3.

当线程0 调用unlock时,会唤醒头部的下个节点head.next() 即等待线程1。当线程1获取到锁的时候 会把自己设置为头部,同时清理它之前的头部节点即上面的new node().

这时链表结构变成:(head)线程1-->等待线程2-->(tail)等待线程3.

同时AQS里面有ConditionObject类,那这个类是干嘛的呢, 这个类不仅有类似object.wait 和 notify的作用。

同时还有指定唤醒哪个线程的作用(一个lock可以有多个condition,一个condition.signal()只能唤醒跟他相同condition.await()的线程,不同condition之间不能唤醒)

ConditionObject类里也有个链表结构condition queue

当获取到锁的线程A调用condition.await()时会创建一个节点加入到condition queue里面;会释放锁同时线程会阻塞。

如果这个时候另外一个线程B获取锁并通过condition.signal()会立刻唤醒A吗,答案是不一定。

因为这时如果wait queue里面有别的等待线程C,D..的话的.就不会马上唤醒A,因为condition.signal()会把线程A加入到wait queue的尾部

4.ReentrantReadWriteLock介绍

ReentrantReadWriteLock是读写锁,作用是

2个线程分别是写锁与写锁,互斥

2个线程分别是读锁与写锁,互斥

2个线程分别是写锁与读锁,互斥(这里要注意下,写入线程获取锁的同时可以再获取读取锁)

2个线程分别是读锁与读锁,异步,非互斥。

独立锁ReentrantLock 通过一个state字段区别锁是否被占用了,那读写锁怎么弄呢?,读锁和写锁应该由2个字段来判断占用的锁是读还是写吧。

显然现在一个state就不够用了。于是在ReentrantReadWrilteLock里面将这个字段一分为二,高位16位表示共享锁的数量,低位16位表示独占锁的数量(或者重入数量)

exclusiveCount是指写锁的数量,sharedCount是读锁的数量。

这里有位运算符,

x>>>y  表示 x向右移动多少位

x<<y  表示 x向左移动多少位

x & y  表示 x二进制和y二进制 相同的位才合并,比如00010001 & 11111001 = 00010001

        /** Read vs write count extraction constants and functions.* Lock state is logically divided into two unsigned shorts:* The lower one representing the exclusive (writer) lock hold count,* and the upper the shared (reader) hold count.*/static final int SHARED_SHIFT   = 16;static final int SHARED_UNIT    = (1 << SHARED_SHIFT);static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;/** Returns the number of shared holds represented in count  */static int sharedCount(int c)    { return c >>> SHARED_SHIFT; }/** Returns the number of exclusive holds represented in count  */static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }

c >>> 16 右移16位, int 是32位,右移16位就是取前16位的值,
c & 2的16次 - 1 相对于c & 01111111 11111111 就是取后16位的值,

转载于:https://www.cnblogs.com/shapeOfMyHeart/p/6667093.html

多线程编程核心技术日记相关推荐

  1. java多线程编程同步方法_实践【Java多线程编程核心技术】系列:同步方法造成的无限等待...

    本文实践来自于[Java多线程编程核心技术]一书! 同步方法容易造成死循环,如-- 类Service.java: package service; public class Service { syn ...

  2. 《Java多线程编程核心技术》——1.5节sleep()方法

    本节书摘来自华章社区<Java多线程编程核心技术>一书中的第1章,第1.5节sleep()方法,作者高洪岩,更多章节内容可以访问云栖社区"华章社区"公众号查看 1.5 ...

  3. 《Java多线程编程核心技术》读书笔记

    为什么80%的码农都做不了架构师?>>>    <Java多线程编程核心技术>读书笔记. ###第一章 Java多线程技能 使用Java多线程两种方式. 继承Thread ...

  4. 多线程编程核心技术总结(读周志明书籍的总结)

    多线程编程核心技术总结 1.Java多线程基本技能 1.1进程和线程的概念: 进程是独立的程序,线程是在进程中独立运行的子任务. 1.2使用多线程 1.2.1实现方法:继承Thread类,重写Runn ...

  5. 《Java多线程编程核心技术》读后感(十一)

    <Java多线程编程核心技术>读后感(十一) 方法join的使用 在很多情况下,主线程创建并启动子线程,如果子线程中要进行大量的耗时运算,主线程往往将早于子线程结束之前结束.这时,如果主线 ...

  6. Java 多线程编程核心技术

    课程介绍 多线程编程在最大限度利用计算资源.提高软件服务质量方面扮演着至关重要的角色,而掌握多线程编程也成为了广大开发人员所必须要具备的技能. 本课程以基本概念.原理方法为主线,每篇文章结合大量演示实 ...

  7. Java多线程编程核心技术-多线程基础使用

    导语   想要学习一个新的技术就必须要无限的接近它,深入的了解它,了解一个东西的步骤就是由浅入深的去深入的了解它.下面这个专题博主会带着大家共同学习Java多线程的核心编程技术,从入门到深入,也欢迎大 ...

  8. java第五章 多线程_java多线程编程核心技术——第五章总结

    定时器Timer的使用 在JDK中Timer类主要负责计划任务的功能,也就是在指定的时间开始执行某一个任务. Timer类的主要作用是设置计划任务,但封装任务的类却是TimerTask类. 执行计划任 ...

  9. java多线程编程核心技术 pdf_Java多线程编程核心技术之volatile关键字

    私信我或关注公众号猿来如此呀,回复:学习,获取免费学习资源包 volatile关键字 关键字volatile的主要作用是使变量在多个线程间可见. 1 关键字volatile与死循环 如果不是在多继承的 ...

  10. 《Java多线程编程核心技术》读后感(十四)

    单例模式与多线程 立即加载/饿汉模式 立即加载就是使用类的时候已经将对象创建完毕,常见的实现办法就是直接new实例化. 立即加载/饿汉模式实在调用方法前,实例已经被创建了 package Six;pu ...

最新文章

  1. 怎么学操作系统和计算机网络?
  2. 大数据分析-裙子颜色蓝黑还是白金是怎么炒作起来的?
  3. Web服务器性能压力测试工具http_load、webbench、ab、Siege使用教程
  4. AFN2.0到3.0的迁移
  5. RS100项目进展更新
  6. [poco] 访问数据库
  7. 《Pytorch - BP全连接神经网络模型》
  8. 在php页面如何调用接口,php之web页面之间的接口调用
  9. C++中的未定义的行为
  10. day08面向对象-内部类、异常
  11. MySQL视图索引与存储过程精析
  12. python:使用sklearn 计算 precision、recall、F1 score(多分类)
  13. CentOS 7 配置免密码证书登录
  14. uniapp更改switch大小
  15. 一个汉字到底是多少个字节
  16. 关于在窗体之间传值的问题 C# winform
  17. EXTREME 设备操作手册
  18. 方舟Mod:任何颜色集
  19. 最全Airtest接口功能介绍和示例总结,新手同学千万不能错过呀!(一)
  20. 怎样利用开源软件赚钱?

热门文章

  1. 为什么私有云的定位应该是PaaS,而不是IaaS?
  2. C++实践參考——二进制文件浏览器
  3. Hibernate学习(一)创建数据表
  4. mysql备份之lvm
  5. openstack nova调用libvirt,跟踪libvirt源码实例详解(cpu_mode及live_migrate 错误解决)...
  6. NGINX(二)内存池
  7. java中实现多线程的两种基本方法
  8. C#中的线程二(Cotrol.BeginInvoke和Control.Invoke)
  9. 用网络附加存储(NAS)构建(本地及远程)、数据容灾
  10. SysUtils.AdjustLineBreaks - Unix 与 Windows 的换行符互换