此文是对《JAVA多线程编程核心技术》的一点总结,如果想要了解具体细节可以去看原书。
第三章 线程间通信
使用wait/notify实现线程间的通信
- 方法wait()的作用是使当前执行代码的线程进行等待,wait()方法是Object类的方法,该方法用来将当前线程置入“预执行队列”中,并且在wait()所在的代码行处停止执行,直到接到通知或中断为止。在调用wait()之前,线程必须获得该对象的对象级别锁,即只能在同步方法或同步块中调用wait()方法。执行wait()方法后,当前线程释放锁。
- 如果调用wait()时没有持有适当的锁,则抛出IllegalMonitorStateException,它是RuntimeException的一个子类,因此,不需要try-catch语句捕获异常。
- 方法notify()也要在同步方法或同步代码块中调用,即在调用前,线程也必须获得该对象的对象级别锁。
- notify()用来通知那些可能等待该对象的对象锁的其他线程,如果有多个线程等待,则由线程规划器随机挑选出一个呈wait状态的线程,对其发出通知notify,并使它等待获取该对象的对象锁
- 在执行notify()方法后,不会马上释放该对象锁,要等到执行notify()方法的线程将程序执行完,当前线程才会释放锁。
线程状态
- 生产者/消费者模式的实现
创建存储值的对象
public class MyStack {
private List list = new ArrayList<>();
synchronized public void push() {
try{
while (list.size() == 1) {
this.wait();
}
list.add("anyString=" + Math.random());
this.notify();
System.out.println("push=" + list.size());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
synchronized public String pop() {
String returnValue = "";
try {
while (list.size() == 0) {
System.out.println("pop操作中的:" + Thread.currentThread().getName() + " 线程呈wait状态");
this.wait();
}
returnValue = "" + list.get(0);
list.remove(0);
this.notify();
System.out.println("pop=" + list.size());
} catch (InterruptedException e) {
e.printStackTrace();
}
return returnValue;
}
}
生产者
/**
* 生产者
*/
public class P {
private MyStack myStack;
public P(MyStack myStack) {
this.myStack = myStack;
}
public void pushService() {
myStack.push();
}
}
生产者线程
public class P_Thread extends Thread {
private P p;
public P_Thread(P p) {
this.p = p;
}
@Override
public void run() {
while (true) {
p.pushService();
}
}
}
消费者
/**
* 消费者
*/
public class C {
private MyStack myStack;
public C(MyStack myStack) {
this.myStack = myStack;
}
public void popService() {
System.out.println("pop=" + myStack.pop());
}
}
消费者线程
public class C_Thread extends Thread {
private C r;
public C_Thread(C r) {
this.r = r;
}
@Override
public void run() {
while (true) {
r.popService();
}
}
}
启动类
public class Run {
public static void main(String[] args) {
MyStack myStack = new MyStack();
P p1 = new P(myStack);
P p2 = new P(myStack);
P p3 = new P(myStack);
P_Thread pThread1 = new P_Thread(p1);
P_Thread pThread2 = new P_Thread(p2);
P_Thread pThread3 = new P_Thread(p3);
pThread1.start();
pThread2.start();
pThread3.start();
C r1 = new C(myStack);
C r2 = new C(myStack);
C r3 = new C(myStack);
C_Thread cThread1 = new C_Thread(r1);
C_Thread cThread2 = new C_Thread(r2);
C_Thread cThread3 = new C_Thread(r3);
cThread1.start();
cThread2.start();
cThread3.start();
}
}
- 方法join的使用
方法join的作用是使所属的线程对象x正常执行run()方法中的任务,而使当前线程z进行无限期的阻塞,等待线程销毁后再执行线程z后面的代码。 - ThreadLocal类的使用
ThreadLocal类主要解决的是每个线程绑定自己的值,可以将ThreadLocal类比喻成全局存放数据的盒子,盒子中可以存储每个线程的私有数据。