线程和进程的区别
- 进程:系统运行的一个应用
- 线程:应用中的一个任务
- 进程要大于线程,一个进程至少一个线程 或 多个线程
如果一个进程,还有一个线程没有杀掉还存活,那么进程还存活(线程依附进程)
并行和并发
- 并行:多个线程同时执行
- 并发:10秒钟,服务器的吞吐量
线程的状态分为六种
- 初始(new):新建一个线程,还没有调用start方法
- 运行(runnable):Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。
线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行中状态(running)。 - 阻塞(blocked):表示线程阻塞于锁
- 等待(waiting):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)
- 超时等待(timed_waiting):该状态不同于waiting,它可以在指定的时间后自行返回
- 终止(terminated):表示该线程已经执行完毕
状态图:
线程的两种启动方式
- 第一种:继承thread
private static class AThread extends Thread {
@Override
public void run() {
super.run();
System.out.println("do work Thread");
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
AThread thread = new AThread();
thread.start();
}
- 第二种:传入runnable
// 方式一:实现Runnable,无返回值
private static class BThread implements Runnable {
@Override
public void run() {
System.out.println("do work Runnable");
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
BThread bThread = new BThread();
new Thread(bThread).start();
}
// 方式二:实现Callable,有返回值
private static class WorkerThread implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("do work WorkerThread");
Thread.sleep(10000);
return "run success"; // 返回值
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
WorkerThread workerThread = new WorkerThread();
// FutureTask实现了Runnable接口
FutureTask<String> futureTask = new FutureTask<>(workerThread);
new Thread(futureTask).start();
System.out.println(futureTask.get());
}
如何停止线程
不要用stop()方法直接停止,要用和谐的方式interrupt()和isInterrupted()
private static class UseThread extends Thread{
public UseThread(String name) {
super(name);
}
@Override
public void run() {
String threadName = Thread.currentThread().getName();
while(!isInterrupted()) { // isInterrupted()默认false,调用了interrupt()就变成true
// 不sleep
// System.out.println("线程内循环运行....");
// sleep
try {
System.out.println("UseThread:"+formater.format(new Date()));
Thread.sleep(3000); // sleep 会把中断信号清除,需要在Exception中再处理一次
} catch (InterruptedException e) {
System.out.println(threadName+" catch interrput flag is "
+isInterrupted()+ " at "
+(formater.format(new Date())));
// interrupt 需要在此内部 调用才能中断了,才能把被清楚的标记修改成true
interrupt();
e.printStackTrace();
}
System.out.println(threadName);
}
System.out.println(threadName+" interrput flag is " +isInterrupted());
}
}
public static void main(String[] args) throws InterruptedException {
Thread useThread = new UseThread("HasInterrputEx");
useThread.start();
Thread.sleep(800);
useThread.interrupt(); //run发放中sleep的话interrupt()会被 InterruptedException e 清除
}
线程优先级 join() 获取执行权
public static void main(String [] args) throws InterruptedException {
ThreadJoinTest t1 = new ThreadJoinTest("A");
ThreadJoinTest t2 = new ThreadJoinTest("B");
t1.start();
/**join的意思是使得放弃当前线程的执行,并返回对应的线程,例如下面代码的意思就是:
程序在main线程中调用t1线程的join方法,则main线程放弃cpu控制权,并返回t1线程继续执行直到线程t1执行完毕
所以结果是t1线程执行完后,才到主线程执行,相当于在main线程中同步t1线程,t1执行完了,main线程才有执行的机会
*/
t1.join(); // 让t1获取执行权
t2.start();
}
总结
- run 和start的区别 ?
run是函数调用 和线程没有任何关系, .start会走底层 会走系统层 最终调度到 run函数,这才是线程。
- 如何控制线程的执行顺序 ?
join来控制 让t2获取执行权力,能够做到顺序执行
- 多线程中的并行和并发是什么?
四个车道,四辆车并行的走,就是并行, 四个车道中,五秒钟多少的车流量,多少的吞吐量一样
- 在Java中能不能指定CPU去执行某个线程?
不能,Java是做不到的,唯一能够去干预的就是C语言调用内核的API去指定才行,这个你回答的话,面试官会觉得你研究点东西
- 在项目开发过程中需要考虑Java线程优先级吗?
不需要考虑优先级, 因为线程的优先级很依赖与系统的平台,所以这个优先级无法对号入座,无法做到你想象中的优先级,属于不稳定,有风险
因为某些开源框架,也不可能依靠线程优先级来,设置自己想要的优先级顺序,这个是不可靠的
例如:Java线程优先级又十级,而此时操作系统优先级只有2~3级,那么就对应不上
- sleep和wait又什么区别?
sleep是休眠,等休眠时间一过,才有执行权的资格,注意:只是又有资格了,并不代表马上就会被执行,什么时候又执行起来,取决于操作系统调度
wait是等待,需要人家来唤醒,唤醒后,才有执行权的资格,注意:只是又有资格了,并不代表马上就会被执行,什么时候又执行起来,取决于操作系统调度
含义的不同:sleep无条件可以休眠, wait是某些原因与条件需要等待一下(资源不满足)
- 在Java中能不能强制中断线程的执行?
虽然提供了 stop 等函数,但是此函数不推荐使用,为什么因为这种暴力的方式,很危险,例如:下载图片5kb,只下载了4kb 等
我们可以使用interrupt来处理线程的停止,但是注意interrupt只是协作式的方式,并不能绝对保证中断,并不是抢占式的
- 如何让出当前线程的执行权?
yield方法,只在JDK某些实现才能看到,是让出执行权
- sleep,wait,到底那个函数才会 清除中断标记?
sleep在抛出异常的时候,捕获异常之前,就已经清除