如何做环保管家网站,搜索引擎营销的主要方式有哪些?,网站如何做流量赚钱吗,小程序是什么技术一、进程通信和进程同步
1.进程通信的方法
同一台计算机的进程通信称为IPC#xff08;Inter-process communication#xff09;#xff0c;不同计 算机之间的进程通信被称为 RPC(Romote process communication)#xff0c;需要通过网络#xff0c;并遵守共同的协议。**进…一、进程通信和进程同步
1.进程通信的方法
同一台计算机的进程通信称为IPCInter-process communication不同计 算机之间的进程通信被称为 RPC(Romote process communication)需要通过网络并遵守共同的协议。**进程通信解决的问题是两个或多个进程间如何交换数据的问题。**常用的进程通信的方法如下
管道分为匿名管道pipe及命名管道named pipe匿名管道可用 于具有亲缘关系的父子进程间的通信命名管道除了具有管道所具有的功能外 它还允许无亲缘关系进程间的通信。信号signal信号是在软件层次上对中断机制的一种模拟它是比较 复杂的通信方式用于通知进程有某事件发生一个进程收到一个信号与处理器 收到一个中断请求效果上可以说是一致的。消息队列message queue消息队列是消息的链接表它克服了上两 种通信方式中信号量有限的缺点具有写权限得进程可以按照一定得规则向消息 队列中添加新信息对消息队列有读权限得进程则可以从消息队列中读取信息。 4. 共享内存shared memory可以说这是最有用的进程间通信方式。它 使得多个进程可以访问同一块内存空间不同进程可以及时看到对方进程中对共 享内存中数据得更新。这种方式需要依靠某种同步操作如互斥锁和信号量等。信号量semaphore主要作为进程之间及同一种进程的不同线程之间的同步和互斥手段。套接字socket这是一种更为一般得进程间通信机制它可用于网络 中不同机器之间的进程间通信应用非常广泛。同一机器中的进程还可以使用 Unix domain socket比如同一机器中 MySQL 中的控制台 mysql shell 和 MySQL 服 务程序的连接这种方式不需要经过网络协议栈不需要打包拆包、计算校验 和、维护序号和应答等比纯粹基于网络的进程间通信肯定效率更高。
2.线程同步的方法
**线程同步解决的问题是多个线程在并发执行过程中需要保持数据一致性和顺序性等问题。**常见的线程同步方法如下
临界区通过对多线程的串行化来访问公共资源或一段代码速度快适合控制数据访问。互斥量为协调共同对一个共享资源的单独访问而设计的。互斥量跟临界区很相似比临界区复杂互斥对象只有一个只有拥有互斥对象的线程才具有访问资源的权限。信号量为控制一个具有有限数量用户资源而设计。它允许多个线程在同一时刻访问同一资源但是需要限制在同一时刻访问此资源的最大线程数目。互斥量是信号量的一种特殊情况当信号量的最大资源数1就是互斥量了。事件 用来通知线程有一些事件已发生从而启动后继任务的开始。
二、创建线程的方法
Java使用Thread类代表线程所有的线程对象都必须是Thread类或其子类的实例。Java可以用四种方式来创建线程如下所示
继承Thread类创建线程实现Runnable接口创建线程使用Callable和Future创建线程使用线程池例如用Executor框架
重点说明(3)使用Callable和Future创建线程。和Runnable接口不一样Callable接口提供了一个call方法作为线程执行体call()方法比run()方法功能要强大其实现了1call()方法可以有返回值2call()方法可以声明抛出异常
Java5提供了Future接口来代表Callable接口里call()方法的返回值并且为Future接口提供了一个实现类FutureTask这个实现类既实现了Future接口还实现了Runnable接口因此可以作为Thread类的target。在Future接口里定义了几个公共方法来控制它关联的Callable任务。 FutureTask的常见方法如下
boolean cancel(boolean mayInterruptIfRunning)视图取消该Future里面关联的Callable任务V get()返回Callable里call方法的返回值调用这个方法会导致程序阻塞必须等到子线程结束后才会得到返回值V get(long timeout,TimeUnit unit)返回Callable里call方法的返回值最多阻塞timeout时间经过指定时间没有返回抛出TimeoutExceptionboolean isDone()若Callable任务完成返回Trueboolean isCancelled()如果在Callable任务正常完成前被取消返回True
介绍了相关的概念之后创建并启动有返回值的线程的步骤如下
创建Callable接口的实现类并实现call()方法然后创建该实现类的实例从java8开始可以直接使用Lambda表达式创建Callable对象。使用FutureTask类来包装Callable对象该FutureTask对象封装了Callable对象的call()方法的返回值使用FutureTask对象作为Thread对象的target创建并启动线程因为FutureTask实现了Runnable接口调用FutureTask对象的get()方法来获得子线程执行结束后的返回值
代码实现
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 {Overridepublic String call() throws Exception {System.out.println(thread running);Thread.sleep(3000);return thread returned;}
}三、线程中run()方法和执行线程start()的区别
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{Overridepublic 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{Overridepublic 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 {Overridepublic 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;}Overridepublic 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;}Overridepublic 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() {Overridepublic 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() {Overridepublic 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 发布