进程与线程
进程就是一个app实例,是资源分配的最小单位
线程是最小的cpu调度单位,线程和进程是包含关系,线程依赖进程
Java当中有进程必然会有线程
进程间的通信:IPC(面试题)
管道:匿名管道(pipe)一般用于父子进程间的通信,父fork一个子进程,子与父进程就没有关系了,如果父子进程之间想要通信的话可以用匿名管道
命名管道(named pipe):就是两个不同进程间想要通信可以共同访问一个命名管道
信号:信号是在软件层次上对中断机制的一种模拟,用于通知进程有事情发生
消息队列:内存中建立起来内存消息队列
共享内存:它可以使多个进程共同访问同一块内存空间
信号量:主要作为进程之间及同一种进程的不同线程之间的同步和互斥手段
套接字:它可以用于网络中不同机器之间的进程通信,基于socket的通信,类似于mysql,既可以本地连接,别的机子也可以访问;这种方式不用经过网络协议栈,不需要打包拆包、计算校验、维护序号和应答等,比纯粹基于网络的进程间通信效率更高
上下文切换
就相当于在代码中写的局部变量,并且并发一定会引起上下文切换
一次上下文切换大概需要5k-2w的时钟周期,因此代码优化的时候需要观察上下文切换的次数
启动线程的方法
继承Thread接口,实现Runnable接口,在run方法中书写业务代码
拿到实例,并new Thread(“xxx”).start启动
官方注释说是两种:new Thread()和实现Runnable接口
此外:Callable接口和线程池也可以启动线程
Callable接口和Future接口
有一个需求:做一个累加,累加完之后,需要拿到累加的结果
Callable 接口可以接收返回值,Runnable接口的run()方法没有返回值
线程是异步执行的,有可能因为休眠的关系,我线程都执行完了,才返回结果
就需要采用Future类的get()方法就可以拿到Callable
Future->RunnableFuture->FurureTask
也就是说需要用FutureTask包装一下Callable
FutureTask<> futureTask = new FutureTask<>(callable);
new Thread(futureTask).start();
futureTask.get();即可拿到返回值
终止线程的方法
自然终止
代码运行结束
代码报错,抛出异常
主动终止
有stop(),挂起suspend()
不过这两个方法都被废弃了,挂起suspend()不会释放任何资源(锁)
stop()太强力了,可能导致写文件时没有正常的结束标志导致文件损坏
一般使用的都是中断方法:interrupt()是用来中断某个线程的,不过它不会立马去中断线程运行,而是会将中断标志位更改为true
interrupted()是用来判断标志位是否为true,判断完之后还会给回false
isinterupted()是用来判断标志位是否为true
不建议自己自定义变量控制线程结束的标志位,因为调用了阻塞类方法除非调用唤醒方法,不然会很迟钝的去感受到这个变量的转化
private static class UseThread extends Thread{
private boolean cancel;
public UseThread(String name) {
super(name);
}
public void setCancel(boolean cancel) {
this.cancel = cancel;
}
@Override
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName+" interrrupt flag ="+isInterrupted());
//while(!isInterrupted()){
//Thread.sleep();
//while(!Thread.interrupted()){
while(true){
System.out.println(threadName+" is running");
System.out.println(threadName+"inner interrrupt flag ="
+isInterrupted());
}
//System.out.println(threadName+" interrrupt flag ="+isInterrupted());
}
}
public static void main(String[] args) throws InterruptedException {
UseThread endThread = new UseThread("endThread");
endThread.start();
Thread.sleep(20);
endThread.interrupt();//中断线程,其实设置线程的中断标识位=true
}
start()和run()方法
连续两次执行start()/run()方法可以吗?
连续执行start()方法会抛出一个异常出来,run()方法则不会,调用几次就执行几次
start()和run()方法的区别是什么
Java是面向对象的语言,将线程抽象成了Thread类,通过new Thread()方法只能说明是JVM堆上面有这么一个对象而已和线程没有关系。把这个对象实例和操作对象的线程挂钩的是调用了start()后才将这个实例和操作系统中的某一个线程挂钩。一个对象实例只能和一个线程对应,所以说不能调用多次start()
run()只是一个成员方法,可以单独反复执行,只是告诉线程该去哪里执行业务代码。