3

Java线程间通信

 2 years ago
source link: https://allenwind.github.io/blog/3993/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Java线程间通信

总结下Java线程间通信的编程技巧。

  • Java中线程处于Runnable状态

    1. 调用sleep方法超过指定时间
    2. 线程调用的阻塞I/O返回
    3. 线程成功获得试图同步的监视器
    4. 线程在等待某个通知,其他线程发出通知
    5. 处于挂起状态调用了resume恢复方法
  • Java中线程处于阻塞状态

    1. 线程调用sleep方法
    2. 线程调用阻塞式I/O,调用返回
    3. 线程试图获取一个同步监视器,但该同步监视器正在被其他线程使用
    4. 线程等他某个通知
    5. 程序调用suspend方法将线程挂起,但谨慎调用该方法。

线程间通信促进资源的共享,加大线程的交互性。

不使用等待/通知机制的线程间通信

不使用等待/通知机制的进行线程间通信可以使用轮询。例子如下:

原理:每个线程都在while循环下轮询共享变量,根据共享变量的值判断下一步的执行。

import java.util.Date;

public class ITCTest {
private static boolean status = true;

private static class Thread1 extends Thread {
public void run() {
while (status) {
System.out.println("time is " + new Date());
}
}
}

public static class Thread2 extends Thread {
public void run() {
while (status) {
System.out.println("time is " + new Date());
}
}
}

public static void main(String[] args) {
Thread t1 = new Thread1();
Thread t2 = new Thread2();

t1.start();
t2.start();

delay();
status = false;
}
}

如果线程轮询时间过小,消耗更大的CPU资源,如果轮询时间过大,则可能错过数据的更新。

等待/通知机制 wait/notify

wait:暂停线程的等待,调用该方法的线程释放共享资源的锁,运行态转换为就绪态,加入等待队列。wait方法可以传入参数,指定等待时间。
notify:通知线程继续运行,随机唤醒等待队列中的一个线程。

注意:调用wait方法会释放锁,但调用notify方法并不释放锁,只有当notify所在的synchronized的代码块被执行完毕后才被调用。

例子: (生产者/消费者模型在代码库中)

public class Task1 extends Thread {
private Object lock;
public Task1(Object lock) {
super();
this.lock = lock;
}

@Override
public void run() {
try {
synchronized (lock) {
System.out.println("A");
lock.wait();
System.out.println("C");
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}

public class Task2 extends Thread {
private Object lock;
public Task2(Object lock) {
super();
this.lock = lock;
}

@Override
public void run() {
synchronized (lock) {
System.out.println("B");
lock.notify();
System.out.println("D");
}
}
}

public class Test {
public static void main(String[] args) {
Object lock = new Object();
Thread t1 = new Task1(lock);
Thread t2 = new Task2(lock);

t1.start();
t2.start();
}
}
  • 当线程在wait()状态下,调用interrupt()方法会出现InterruptedException异常。

通过管道进行线程通信

这部分参考IO模块的实现

join方法的使用

阻塞当前调用join的线程,直到被阻塞的线程返回。可以传入long类型的参数指定timeout参数。

  • join 方法的内部实现采用 wait
  • sleep 方法调用后不释放锁

ThreadLocal

ThreadLocal线程本地:每个线程都有同一个变量的独有拷贝。拥有get、set接口。

实现原理

有一个Map维护线程对象和值的映射。

public class ThreadLocalBasic {
static ThreadLocal<Integer> local = new ThreadLocal<>();

public static void main(String[] args) throws InterruptedException {
Thread child = new Thread() {
@Override
public void run() {
System.out.println("child thread initial: " + local.get());
local.set(200);
System.out.println("child thread final: " + local.get());
}
};

local.set(100);
child.start();
child.join();
System.out.println("main thread final: " + local.get());
}
}



About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK