第一章 java多线程技能
- 进程是受操作系统管理的基本运行单元,它受系统进行资源分配和调度的一个独立单元。
- 线程是进程中独立运行的子任务。
- main函数也是一个进程,并且有一个main线程。
- isAlive()方法判断当前的线程是否处于活动状态,也就是线程已经启动且尚未终止状态。
- 停止线程:interrupt()方法停止线程,并不会真正停止线程,而是加一个停止标记。 interrupted()方法测试当前线程是否已经是中断状态,执行后具有将状态标志置清除为false的功能。isInterrupted()方法测试线程对象是否已经是中断状态,但不清除状态标志。stop()方法已经废弃,废弃原因1.可能使一些清理性的工作得不到完成;2.对锁定的对象会进行解锁导致数据得不到同步处理,出现数据不一致的问题。
- 暂停线程:suspend()和resume()方法已经废弃,废弃原因:1.容易造成锁的独占2.出现数据不同步
- yield()方法的作用是放弃当前的cup资源,让给其他的任务区占用cpu执行时间,但放弃时间不确定,有可能立马又获取cpu时间片。
- 线程的优先级分为1~10个等级。线程优先级高的线程得到的cpu资源较多,也就是cpu优先执行优先级较高的线程对象中的任务。线程优先级具有继承性,规则性,随机性。继承性:a线程启动b线程,b线程默认优先级和a一样。规则性:cpu尽量将执行资源让给优先级比较高的线程。随机性:并不是优先级越高就一定先执行,只是大概率获取cpu资源。
- 守护线程。当进程中不存在非守护线程,守护线程自动销毁。
- println方法在多线程中有可能阻塞
public void println(String x) {
synchronized (this) {
print(x);
newLine();
}
}
第二章 对象及变量的并发访问
- 可重入锁:自己可以再次获取自己的内部锁。如果不可重入的话会造成死锁。
- synchronized同步方法:1对其他synchronized同步方法和synchronized(this)同步块调用呈阻塞状态2.同一时间只有一个线程可以执行synchronized同步方法中的代码
- synchronized(this)同步代码块:1对其他synchronized同步方法和synchronized(this)同步块调用呈阻塞状态2.同一时间只有一个线程可以执行synchronized(this)同步代码块中的代码
- 静态同步synchronized方法和synchronized(class)代码块对Class类进行持锁,而不是对象。
- 由于在jvm中具有Stirng常量池缓存对功能,所以大部分情况,synchronized代码块尽量不要使用Stirng对象进行加锁,可以new Object()来使用。
- volatile 解决了变量在多线程间对可见性。关键字volatile对作用是强制从公共堆栈中取得变量对值,而不是从线程私有数据栈中取得变量对值。
第三章 线程间通信
- 等待/通知机制 在执行wait()方法之前,线程必须获得该对象对对象级锁,执行wait()方法后,当前线程立即释放锁。在执行notify()方法之前,线程必须获得该对象对对象级锁,执行notify()方法后,当前线程不会立即释放该对象锁,而是要将程序执行完。
- 生产者/消费者模式,多生产者/消费者情况下为了防止假死状态使用notifyAll
package com.zlc.jzlc;
public class ValueObject {
public static String value = "";
}
代码语言:javascript复制package com.zlc.jzlc;
public class P {
private String lock;
public P(String lock) {
this.lock = lock;
}
public void setValue() {
try {
synchronized (lock) {
if (!ValueObject.value.equals("")) {
lock.wait();
}
String value = System.currentTimeMillis() "_" System.nanoTime();
System.out.println("P set:" value);
ValueObject.value = value;
lock.notify();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
代码语言:javascript复制package com.zlc.jzlc;
public class C {
private String lock;
public C(String lock) {
this.lock = lock;
}
public void getValue() {
try {
synchronized (lock) {
if (ValueObject.value.equals("")) {
lock.wait();
}
System.out.println("C get:" ValueObject.value);
ValueObject.value = "";
lock.notify();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
代码语言:javascript复制package com.zlc.jzlc;
public class ThreadP extends Thread {
private P p;
public ThreadP(P p) {
this.p = p;
}
public void run() {
while (true) {
p.setValue();
}
}
}
代码语言:javascript复制package com.zlc.jzlc;
public class ThreadC extends Thread {
private C c;
public ThreadC(C c) {
this.c = c;
}
public void run() {
while (true) {
c.getValue();
}
}
}
代码语言:javascript复制package com.zlc.jzlc;
public class PCTest {
public static void main(String[] args) {
String lock = new String("");
P p = new P(lock);
C c = new C(lock);
ThreadP tp = new ThreadP(p);
ThreadC tc = new ThreadC(c);
tp.start();
tc.start();
}
}
- 通过管道进行线程间通信:字节流/字符流
- ThreadLocal生成副本,每个副本都是独立的。
- join()方法内部实现是wait/notify 使所属的线程对象x正常执行run()方法中的任务,而使当前线程z进行无限期的阻塞,等待线程x销毁后再继续执行线程z后面的代码。
第四章 Lock的使用
- 公平锁表示线程获取锁的顺序是按照线程加锁的顺序来分配的,即先来先得的fifo先进先出顺序。而非公平锁不一定先来先得到。
- 读写锁。读锁也即共享锁。写锁也即排他锁。读读不互斥,读写互斥,写写互斥。
其他
- 完美单例 使用DCL双检查锁机制
package com.zlc.jzlc;
public class MyObject {
private volatile static MyObject myObject;
private MyObject() {
}
public static MyObject getInstance() {
try {
if (myObject == null) {
//do some things
synchronized (MyObject.class) {
if (myObject == null) {
myObject = new MyObject();
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return myObject;
}
}
- 线程间的几种不同状态
- 有序列表项1新建状态(New):新创建了一个线程对象。
- 就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
- 运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
- 阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种: (一)、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。 (二)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。 (三)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
- 死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。