多线程编程核心技术日记
第一章
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
多线程编程核心技术日记相关推荐
- java多线程编程同步方法_实践【Java多线程编程核心技术】系列:同步方法造成的无限等待...
本文实践来自于[Java多线程编程核心技术]一书! 同步方法容易造成死循环,如-- 类Service.java: package service; public class Service { syn ...
- 《Java多线程编程核心技术》——1.5节sleep()方法
本节书摘来自华章社区<Java多线程编程核心技术>一书中的第1章,第1.5节sleep()方法,作者高洪岩,更多章节内容可以访问云栖社区"华章社区"公众号查看 1.5 ...
- 《Java多线程编程核心技术》读书笔记
为什么80%的码农都做不了架构师?>>> <Java多线程编程核心技术>读书笔记. ###第一章 Java多线程技能 使用Java多线程两种方式. 继承Thread ...
- 多线程编程核心技术总结(读周志明书籍的总结)
多线程编程核心技术总结 1.Java多线程基本技能 1.1进程和线程的概念: 进程是独立的程序,线程是在进程中独立运行的子任务. 1.2使用多线程 1.2.1实现方法:继承Thread类,重写Runn ...
- 《Java多线程编程核心技术》读后感(十一)
<Java多线程编程核心技术>读后感(十一) 方法join的使用 在很多情况下,主线程创建并启动子线程,如果子线程中要进行大量的耗时运算,主线程往往将早于子线程结束之前结束.这时,如果主线 ...
- Java 多线程编程核心技术
课程介绍 多线程编程在最大限度利用计算资源.提高软件服务质量方面扮演着至关重要的角色,而掌握多线程编程也成为了广大开发人员所必须要具备的技能. 本课程以基本概念.原理方法为主线,每篇文章结合大量演示实 ...
- Java多线程编程核心技术-多线程基础使用
导语 想要学习一个新的技术就必须要无限的接近它,深入的了解它,了解一个东西的步骤就是由浅入深的去深入的了解它.下面这个专题博主会带着大家共同学习Java多线程的核心编程技术,从入门到深入,也欢迎大 ...
- java第五章 多线程_java多线程编程核心技术——第五章总结
定时器Timer的使用 在JDK中Timer类主要负责计划任务的功能,也就是在指定的时间开始执行某一个任务. Timer类的主要作用是设置计划任务,但封装任务的类却是TimerTask类. 执行计划任 ...
- java多线程编程核心技术 pdf_Java多线程编程核心技术之volatile关键字
私信我或关注公众号猿来如此呀,回复:学习,获取免费学习资源包 volatile关键字 关键字volatile的主要作用是使变量在多个线程间可见. 1 关键字volatile与死循环 如果不是在多继承的 ...
- 《Java多线程编程核心技术》读后感(十四)
单例模式与多线程 立即加载/饿汉模式 立即加载就是使用类的时候已经将对象创建完毕,常见的实现办法就是直接new实例化. 立即加载/饿汉模式实在调用方法前,实例已经被创建了 package Six;pu ...
最新文章
- 怎么学操作系统和计算机网络?
- 大数据分析-裙子颜色蓝黑还是白金是怎么炒作起来的?
- Web服务器性能压力测试工具http_load、webbench、ab、Siege使用教程
- AFN2.0到3.0的迁移
- RS100项目进展更新
- [poco] 访问数据库
- 《Pytorch - BP全连接神经网络模型》
- 在php页面如何调用接口,php之web页面之间的接口调用
- C++中的未定义的行为
- day08面向对象-内部类、异常
- MySQL视图索引与存储过程精析
- python:使用sklearn 计算 precision、recall、F1 score(多分类)
- CentOS 7 配置免密码证书登录
- uniapp更改switch大小
- 一个汉字到底是多少个字节
- 关于在窗体之间传值的问题 C# winform
- EXTREME 设备操作手册
- 方舟Mod:任何颜色集
- 最全Airtest接口功能介绍和示例总结,新手同学千万不能错过呀!(一)
- 怎样利用开源软件赚钱?
热门文章
- 为什么私有云的定位应该是PaaS,而不是IaaS?
- C++实践參考——二进制文件浏览器
- Hibernate学习(一)创建数据表
- mysql备份之lvm
- openstack nova调用libvirt,跟踪libvirt源码实例详解(cpu_mode及live_migrate 错误解决)...
- NGINX(二)内存池
- java中实现多线程的两种基本方法
- C#中的线程二(Cotrol.BeginInvoke和Control.Invoke)
- 用网络附加存储(NAS)构建(本地及远程)、数据容灾
- SysUtils.AdjustLineBreaks - Unix 与 Windows 的换行符互换