1.进程通信的方法
同一台计算机的进程通信称为IPC(Inter-process communication),不同计 算机之间的进程通信被称为 RPC(Romote process communication),需要通过网络,并遵守共同的协议。**进程通信解决的问题是两个或多个进程间如何交换数据的问题。**常用的进程通信的方法如下:
2.线程同步的方法
**线程同步解决的问题是多个线程在并发执行过程中需要保持数据一致性和顺序性等问题。**常见的线程同步方法如下:
Java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。Java可以用四种方式来创建线程,如下所示:
重点说明(3)使用Callable和Future创建线程。和Runnable接口不一样,Callable接口提供了一个call()方法作为线程执行体,call()方法比run()方法功能要强大,其实现了(1)call()方法可以有返回值;(2)call()方法可以声明抛出异常;
Java5提供了Future接口来代表Callable接口里call()方法的返回值,并且为Future接口提供了一个实现类FutureTask,这个实现类既实现了Future接口,还实现了Runnable接口,因此可以作为Thread类的target。在Future接口里定义了几个公共方法来控制它关联的Callable任务。
FutureTask的常见方法如下:
介绍了相关的概念之后,创建并启动有返回值的线程的步骤如下:
代码实现:
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class MyCallableTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask futureTask = new FutureTask<>(new MyCallableThread());
Thread thread = new Thread(futureTask);
thread.start();
String result = futureTask.get();
System.out.println(result);
}
}
class MyCallableThread implements Callable {
@Override
public String call() throws Exception {
System.out.println("thread running");
Thread.sleep(3000);
return "thread returned";
}
}
Thread类是Java里对线程概念的抽象,可以这样理解:我们通过new Thread()其实只是new出一个Thread的实例,还没有操作系统中真正的线程关联起来。只有执行了start()方法后,才实现了真正意义上的启动线程。
从Thread的源码可以看到,Thread的start方法中调用了start0()方法,而start0()是个native方法,这就说明Thread#start一定和操作系统是密切相关的。
Thread类中的run()方法中说明的是任务的处理逻辑,执行线程的start()方法让一个线程进入就绪队列等待分配cpu,分到cpu后才调用实现的run()方法,执行任务的处理逻辑,start()方法不能重复调用,如果重复调用会抛出异常。而run方法是业务逻辑实现的地方,本质上和任意一个类的任意一个成员方法并没有任何区别,可以重复执行,也可以被单独调用。
1.自然终止
要么是run执行完成了,要么是抛出了一个未处理的异常导致线程提前结束。
2.调用stop等方法
暂停、恢复和停止操作对应在线程Thread的API就是suspend()、resume()和stop()。但是这些API是过期的,也就是不建议使用的。不建议使用的原因主要有:以suspend()方法为例,在调用后,线程不会释放已经占有的资源(比如锁),而是占有着资源进入睡眠状态,这样容易引发死锁问题。同样,stop()方法在终结一个线程时不会保证线程的资源正常释放,通常是没有给予线程完成资源释放工作的机会,因此会导致程序可能工作在不确定状态下。正因为suspend()、resume()和stop()方法带来的副作用,这些方法才被标注为不建议使用的过期方法。
public class MyThreadTest1 {
public static void main(String[] args) {
Thread thread = new Thread(new MyTask());
thread.start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.stop();
}
}
class MyTask implements Runnable{
@Override
public void run() {
while (true) {
System.out.println("thread runing: " + Thread.currentThread().getName());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
3.使用thread.interrupt()中断方法
安全的停止线程方式是使用thread.interrupt()中断来停止。在主线程中调用thread.interrupt()方法,能够将thread的中断标识设置为false,再在当前线程中调用Thread.currentThread().isInterrupted()判断是否中断,从而判断是否结束线程。
值得注意的是如果一个线程处于了阻塞状态(如线程调用了thread.sleep、thread.join、thread.wait等),则在线程在检查中断标示时如果发现中断标示为true,则会在这些阻塞方法调用处抛出InterruptedException异常,并且在抛出异常后会立即将线程的中断标示位清除,即重新设置为false,所以需要Thread.currentThread().interrupt()重新再设置一下。
代码实现:
public class MyTest1 {
public static void main(String[] args) {
Thread thread = new Thread(new MyTaskTest());
thread.start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
System.out.println("mainThread end");
}
}
class MyTaskTest implements Runnable{
@Override
public void run() {
boolean interrupted = Thread.currentThread().isInterrupted();
while (!interrupted) {
interrupted = Thread.currentThread().isInterrupted();
System.out.println("interrupted = " + interrupted);
System.out.println("subThread running");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// e.printStackTrace();
Thread.currentThread().interrupt();
System.out.println("interrupted = " + interrupted);
}
}
}
}
thread.join()
join()是进行线程同步的方法,通过在当前线程中执行另一个线程的thread.join()方法,可以等待另一个线程执行完成之后,当前线程才执行,通过这样的方式来控制两个线程的先后顺序。
以下代码通过join()方法实现了thread1–>thread2–>thread3按照顺序来执行的逻辑。
public class MyJoinTest {
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new MyTask1());
Thread thread2 = new Thread(new MyTask2(thread1));
Thread thread3 = new Thread(new MyTask3(thread2));
thread1.start();
thread2.start();
thread3.start();
thread3.join();
System.out.println("main end");
}
}
class MyTask1 implements Runnable {
@Override
public void run() {
System.out.println("thread:" + Thread.currentThread().getName());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class MyTask2 implements Runnable {
Thread thread;
public MyTask2(Thread thread) {
this.thread = thread;
}
@Override
public void run() {
try {
thread.join();
System.out.println("thread:" + Thread.currentThread().getName());
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class MyTask3 implements Runnable {
Thread thread;
public MyTask3(Thread thread) {
this.thread = thread;
}
@Override
public void run() {
try {
thread.join();
System.out.println("thread:" + Thread.currentThread().getName());
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
wait()/notiyf()
通过wait()/notiyf()来实现等待/通知模型,是指一个线程A调用了对象O的wait()方法进入等待状态,而另一个线程B调用了对象O的notify()或者notifyAll()方法,线程A收到通知后从对象O的wait()方法返回,进而执行后续操作。上述两个线程通过对象O来完成交互,而对象上的wait()和notify/notifyAll()的关系就如同开关信号一样,用来完成等待方和通知方之间的交互工作。
wait()方法:调用该方法的线程进入 WAITING状态,只有等待另外线程的通知或被中断才会返回.需要注意,调用wait()方法后,会释放对象的锁
notify()方法:通知一个在对象上等待的线程,使其从wait方法返回,而返回的前提是该线程获取到了对象的锁,没有获得锁的线程重新进入WAITING状态。
等待/通知模型说明:
等待方:
(1) 获取对象的锁。
(2) 如果条件不满足,那么调用对象的wait()方法,此时会释放锁。
(3) 竞争到锁并且条件满足,则执行对应的逻辑。
synchronized(lock){
while(条件不满足){
lock.wait()
}
业务逻辑
}
通知方:
(1) 获得对象的锁。
(2) 改变条件。
(3) 通知所有等待在对象上的线程,并释放锁。
synchronized(lock){
改变条件,满足条件
lock.notify()
}
以下代码实现:等待方等待通知方改变条件,满足条件后才执行后面的业务逻辑
public class MyWaitNotifyTest {
public static Object lock = new Object();
public static boolean flag = false;
public static void main(String[] args) {
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock) {
System.out.println("等待方:我想要执行");
while (!flag) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("等待方:正常执行了");
}
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock) {
flag = true;
lock.notify();
System.out.println("通知方:可以执行了");
}
}
});
thread1.start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread2.start();
}
}
本文由博客一文多发平台 OpenWrite 发布!