通知方依照如下原则:
获得对象的锁改变条件通知所有期待在对象上的线程。
对应伪代码分别如下:
使用synchronized方法:
synchronized(对象){
改变条件
对象.notifyAll()
}

使用lock模式:
lock.lock();
try{
改变条件
condition.singleAll();
}finally{
lock.unlock();
}
除了使用下面我们介绍的经典模式以外,我们还可以使用Thread.join()方法。join方法的使用意义如下:
当线程A调用线程B对象(bThread)的join方法,其意义是当前线程A等待线程B终止后,才从线程A中bThread.join()代码的调用处返回。线程除了join方法以外还提供了join(long millis)和void join(long millis, int nanos)这两个具备超时特性的方式。这两个方法的含义是即使在给定的时间内线程B没有终止。那么线程A将会从该方式中返回。下面我们来看一下join方法的使用实例,如下所示:
class AThread extends Thread {
public AThread() {
super("[AThread]”);
}
@Override
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + "-->start”);
try {
for (int i = 0; i < 5; i++) {
System.out.println(threadName + "loop at" + i);
TimeUnit.SECONDS.sleep(1);
}
System.out.println(threadName + "--->end”);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class BThread extends Thread {
private AThread mAThread;
public BThread(AThread aThread) {
super("[BThread]”);
this.mAThread = aThread;
}
@Override
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + "-->start”);
try {
mAThread.join();//使B线程等待,需要等待A线程执行完毕后,才能继续执行
System.out.println(threadName + "--->end”);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class ThreadJoinDemo {
public static void main(String[] args) throws InterruptedException {
System.out.println(Thread.currentThread().getName() + "-->start”);
AThread aThread = new AThread();
BThread bThread = new BThread(aThread);
try {
aThread.start();
TimeUnit.SECONDS.sleep(1);
bThread.start();
aThread.join();//主线程等待A线程执行完毕后,才继续执行
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "--->end”);
}
}
在上述事例中,我们主要推动下面两个效果:
我们查看输出结果:
main-->start //main线程启动
[AThread]-->start //A线程启动
[AThread]loop at0 //A线程开始执行循环
[AThread]loop at1
[BThread]-->start //B线程开始启动,因为在B线程中调用了aThread.join()那么B线程会等待A线程执行完毕后,才开始执行
[AThread]loop at2 //A线程继续执行
[AThread]loop at3
[AThread]loop at4
[AThread]--->end //A线程执行完毕后,
[BThread]--->end //A线程执行完毕后,唤醒B线程继续执行
main--->end //主线程执行完毕
整个程序是根据我们之前的逻辑在运行,下面我们来查看线程中join方法的实现机理,具体代码如下所示:
join()方法内部会调用join(final long millis)方法。
//同步方法默认的锁为调用该方法的对象,也就是xxThread.join()的xxThread
public final synchronized void join(final long millis)
throws InterruptedException {
if (millis > 0) {//如果等待时间大于0
if (isAlive()) {
final long startTime = System.nanoTime();
long delay = millis;
do {
wait(delay);
} while (isAlive() && (delay = millis -
TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)) > 0);
}
} else if (millis == 0) {//如果等待时间为0,
while (isAlive()) {
wait(0);//当前线程存活,那么会使当前线程等待(当前线程指运行xxThread.join的线程,而不是xxThread)
}
} else {
throw new IllegalArgumentException("timeout value is negative”);
}
}
我们简单的剖析一下代码,当B线程读取A线程的join()方法时,当前锁对象为A线程。在join()方法内部会调用wait(0),该方式会使B线程等待。只有当A线程执行完毕后,也就是A线程中止后。才会激活B线程。
线程执行完毕或轮询终止时,会读取线程自身的notifyAll()方法,会通知所有期待在该线程对象的线程。
在上述文章中,我们都是讲解的多个线程之前的通信,那么在同一线程中,在某个时刻我们想获得线程中修改的数组,我们可以借助ThreadLocal,在之前的文章中Android-Handler机制之ThreadLocal,我们介绍过ThreadLocal的使用。下面我们借助一个例子来认识ThreadLocal的使用。具体实例如下:
class ThreadLocalTest {
private static ThreadLocal<String> mThreadLocal = new ThreadLocal<>();
public static void main(String[] args) {
mThreadLocal.set("线程main”);
new Thread(new A()).start();
new Thread(new B()).start();
System.out.println(mThreadLocal.get());
}
static class A implements Runnable {
@Override
public void run() {
mThreadLocal.set("线程A”);
System.out.println(mThreadLocal.get());
}
}
static class B implements Runnable {
@Override
public void run() {
mThreadLocal.set("线程B”);
System.out.println(mThreadLocal.get());
}
}
}
输出结果:
main
线程A
线程B
这里就不再介绍ThreadLocal的原理了,有兴趣的小伙伴可以查看Android-Handler机制之ThreadLocal文章进行理解。
这里提供一个线程交替打印素数偶数的举例,来帮助你们巩固所学的知识点。有兴趣的小伙伴,可以查看项目PrintOddEventNumber。
该文章参考下面图书,站在巨人的大腿上。可以看得更远。
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-120751-3.html
它也不敢
怎么也没法输入