Please enable JavaScript.
Coggle requires JavaScript to display documents.
Java多线程
外练互斥,内练可见 (概念和优点 (停止线程 (判断线程是否停止方法 (this.interrupted() …
Java多线程
外练互斥,内练可见
概念和优点
-
-
sleep() 方法
在指定的毫秒数内让当前“正在执行的线程”休眠(暂停执行),这个正在执行的线程指: this.currentThread
-
停止线程
-
-
判断线程是否停止方法
this.interrupted() 测试当前线程是否中断。执行后具有将状态标志清楚为false的功能。
interrupted方法具有清除状态的功能,连续两次调用,无论第一次是什么值,第二次都会返回false
-
-
-
-
-
线程的优先级
-
-
-
优先级的继承特性: 线程的优先级具有继承性。eg.A线程启动B线程,所以B线程的优先级和A线程是一样的。
线程优先级的随机性:一般来说线程优先级搞的线程通常优先执行完run()方法,但是这个结果不是肯定的,优先级具有随机性,不一定每次结果都先完成。
-
对象变量的并发访问
synchronized同步方法
非线程安全:多个线程对同一对象中的实列变量并发访问时,产生“脏读”的后果,也就时取到的数据其实时被更改过的。
线程安全: 就是多线程并发访问同一对象的实例变量的时候,变量的值经过同步处理,不会出现脏读的现象。
-
-
关于脏读
当A 线程调用anyObject对象加入synchronized关键字的X方法时,A线程就获得了X方法锁,更准确的说时获得了对象锁,所以其他线程必须等待A线程执行完毕以后才能调用X方法,但是B线程可以随意调用其他的非sychronized同步方法方法。
当线程调用anyObject对象加入synchronized关键字的X方法时,A线程就获取了X方法所在的对象的锁,所以其他线程必须等待A线程执行完毕以后才能调用X方法,而B线程如果调用声明了synchronized关键字的非X方法时,必须等A线程将X方法执行完成,也就是等A线程释放对象锁之后才能调用。
synchronized锁重入
就是在使用synchronized时,当一个线程得到一个对象锁之后,再次请求此对象锁时时可以再次得到该对象的锁的。这也证明了一个synchronized方法/块的内部调用本类的其他synchronized方法/块时,是永远可以得到锁的。
-
-
-
synchronized代码块之间的同步性
synchronized(this) 代码块需要注意的是,当一个线程访问object的一个synchronized(this)同步代码块的时候,其他线程对同一个object中所有其他的synchronized(this)同步代码块的访问将被阻塞,这说明synchronized使用的“对象监视器”是一个。
将任意对象作为对象监视器
-
synchronized同步方法: 对其他的synchronized同步方法或者synchronized(this)同步块代码调用呈阻塞状。
同一时间只有一个线程执行synchronized同步方法中的代码。
synchronized(this)同步块: 对于其他的synchronized同步方法或者synchronized(this)同步块代码的调用呈阻塞状。
同一时间只有一个线程可以执行synchronized(this)同步代码块。
-
-
-
-
-
volatile关键字
-
volatile关键字的作用: 强制从公共堆栈中取得变量的值,从而不是从线程私有数据栈中取得变量的值。使用volatile关键字增加了实例变量在多个线程之间的可见性。
不使用volatile关键字,线程将指挥从自己的私有栈中取变量值,而不从公共堆栈取值,这就可能造成死循环。
-
volatile非原子性特征
-
-
volatile 提示线程每次从共享内存中读取变量值,而不是从私有的内存中读取,这样保证了同步数据的可见性。
但是,需要注意,如果修改实例变量中的数据,比如 i++ 也就是
i = i+1 ,这样的操作并不是一个原子性操作,也就是非安全的。这个表达式操作的步骤分解如下:
- 从内存中取出i
- 计算i的值
- 将i的值写入内存
假如在第二步的时候,另一个线程也修改i的值,那么这个时候就会出现脏读的数据。解决的办法就是使用synchronized关键字。
-
-
线程通信
等待/通知机制
-
等待通知机制的实现
方法wiat() 的作用就是使当前线程进行等待, wait方法是object类的方法,该方法用来将当前线程置入"预执行队列"中,并且在wiat() 所在的代码处停止执行,直到接到通知或者被中断为止。
在从wait()返回前,线程必须获得该对象的对象级锁,即只能在同步方法或者同步块中调用wait()方法。在执行wait()方法后,当前线程释放锁。在从wait() 返回前,线程与其他线程竞争重新获取锁。如果调用wait()时没有持有适当的锁,则抛出IllegalMonitorStateException异常,这个异常不需要try捕获,因为它时RuntimeException的子类。
方法notify()也要在同步方法或者同步块中调用,即在调用前,线程必须获得该对象的对象级锁。如果调用notify()时没有持有适当的锁,也会抛出IllegalMonitorStateException异常。
该方法用来通知那些可能等待对象的对象锁的其他线程,如果有多个线程等待,则由线程规划器随机挑选出其中一个呈wait状态的线程,对其发出通知notify,并使它等待获取该对象的对象锁。
需要说明的使,在执行notify()后,当前线程不会马上释放该对象锁,呈wait状态的线程也不能马上获得该对象锁,要等到执行notify()方法的线程将程序执行完,也就是退出synchronied代码块后,当前线程才会释放锁,而呈wait状态的线程才可以获取该对象锁。当第一个获得了该对象锁的wait线程运行完毕以后,它会释放该对象锁,此时如果该对象没有再次使用notify()语句,则即便该对象已经空闲,其他wait状态等待的线程由于没有得到该对象的通知,还会继续阻塞在wait状态,直到这个对象发出一个notify或者notifyAll。
-
关键字synchronized可以将任何一个object对象作为同步对象来看待,而Java的每个object都实现了wait() 和 notify()方法,他们必须用在被synchronized同步的object的区域内。通过调用wait方方法可以使处于同步方法的线程进入等待状态,同时释放同步对象的锁。而notify操作可以唤醒一个因调用了wait方法处于阻塞状态的线程,使其进入就绪状态。被重新唤醒的线程会试图重新获取锁,并继续执行wait之后的代码,如果notify发出以后没有处于wait状态的线程,那么该命令被忽略。
wait()方法 使调用该方法的线程释放公共的资源锁,然后从运行状态退出,进入等待状态。
notify() 可以随机唤醒等待列队中等待同一个资源的"一个"线程,并使该线程退出等待队列,进入可运行状态,也就是notify() 方法仅通知一个线程。
notifyAll() 可以使所有正在等待的队列中等待同一个共享资源的“全部”线程从等待状态退出,进入可运行状态。 此时,优先级最高的那个线程优先执行,但也有可能使随机执行,这取决于JVM。
每个锁对象有两个队列。 一个就是就绪队列,一个就是阻塞队列。
就绪队列存储了将要获得锁的线程;阻塞队列存储了被阻塞的线程;
一个线程被唤醒以后,才会进入就绪队列,等待CPU的调度;反之,一个线程被wait之后,就会进入阻塞队列,等待下一次被唤醒。
-
方法join的使用
-
方法join 解决主线程等待子线程执行完毕
-
方法join具有是线程排队的作用,有些类似同步运行的效果。join 和 synchronized的区别使: join在内部使用wait方法进行等待,而synchronized关键字使用的是“对象监视器”原理做同步。