笔记:线程小白基础
进程与线程的区别
1.进程:操作系统调度的最小单元 如任务管理器里每一个应用就是一个进程
2.线程:CPU调度的最小单元,一个进程通常可以包含多个线程。
线程间的调度机制
1.线程间在cpu调度采用的算法是RR调度,由于每一次切换都是一次上下文切换 需要临时存储和获取将停止线程与将执行线程的数据 所以每次切换都是需要耗费性能。
2.线程调度——时间片轮转/CPU核心调度
线程调度
线程的并发与并行
-
并发:一段时间内处理了多少数据(如服务器10s内的吞吐量)
并发.png
-
并行 : 同一时间 几个人同时进行(一个跑道上几个人同时在跑)
并行.png
创建与启动线程的三种方式
- 继承Thread(xxx extends Thread)
class MyThread extends Thread{
@Override
public void run() {
System.out.println("MyThread=======================>"+getName());
}
}
//TODO: 继承Thread
MyThread myThread = new MyThread();
myThread.start();
- 无返回结果 实现Runnable(xxxx implements Runnable)
class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println("MyRunnable=======================>"+Thread.currentThread().getName());
}
}
//TODO: 实现Runnable
MyRunnable myRunnable = new MyRunnable();
new Thread(myRunnable).start();
- 有返回结果 实现Callable(xxx implements Callable)
class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("MyCallable=======================>"+Thread.currentThread().getName());
return "MyCallable";
}
}
//TODO: 附带返回值实现Callable
MyCallable myCallable = new MyCallable();
FutureTask<String> futureTask = new FutureTask<>(myCallable);
new Thread(futureTask).start();
try {
System.out.println(futureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
控制台打印
线程的中止
1.抢占式停止stop()(不安全,不推荐)
2.协作式停止 interrupt()
class MyThread extends Thread{
@Override
public void run() {
int i=0;
while (!isInterrupted()){
i++;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
interrupt();
}
System.out.println("MyThread=======================>"+i+" "+getName());
}
}
}
发起中断信号
myThread.start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//TODO: 发起中断
myThread.interrupt();
线程中止
线程的常用方法
线程常用方法.png
-
join() 获取线程执行权
Thread threadA = new Thread(){
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("HELLO TA");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Thread threadB = new Thread(){
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("HELLO TB");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
threadA.start();
threadB.start();
结果:
抢占式无序.png
threadA.start();
try {
threadA.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
threadB.start();
结果:
使用join.png
-
yeild():让出线程执行权
-
wait():等待唤醒
-
notify():通知
-
notifyAll():通知全部
-
sleep():休眠时间到自动回到可执行状态
面试题:
-
TODO 【面试题】 就是 run 和start的区别 ?
答:run是函数调用 和线程没有任何关系, .start会走底层 会走系统层 最终调度到 run函数,这才是线程。
-
TODO 【面试题】 如何控制线程的执行顺序 ?
答:join来控制 让t2获取执行权力,能够做到顺序执行
-
TODO 【面试题】 多线程中的并行和并发是什么?
答:四个车道,四辆车并行的走,就是并行, 四个车道中,五秒钟多少的车流量,多少的吞吐量一样
-
TODO 【面试题】在Java中能不能指定CPU去执行某个线程?
答:不能,Java是做不到的,唯一能够去干预的就是C语言调用内核的API去指定才行
-
TODO【面试题】在项目开发过程中,你会考虑Java线程优先级吗?
答:不会考虑优先级,为什么呢? 因为线程的优先级很依赖与系统的平台,所以这个优先级无法对号入座,无法做到你想象中的优先级,属于不稳定,有风险 因为某些开源框架,也不可能依靠线程优先级来,设置自己想要的优先级顺序,这个是不可靠的。 例如:Java线程优先级又十级,而此时操作系统优先级只有2~3级,那么就对应不上
-
TODO 【面试题】sleep和wait又什么区别?
答:sleep是休眠,等休眠时间一过,才有执行权的资格,注意:只是又有资格了,并不代表马上就会被执行,什么时候又执行起来,取决于操作系统调度
wait是等待,需要人家来唤醒,唤醒后,才有执行权的资格,注意:只是又有资格了,并不代表马上就会被执行,什么时候又执行起来,取决于操作系统调度
含义的不同:sleep无条件可以休眠, wait是某些原因与条件需要等待一下(资源不满足)
-
TODO 【面试题】 在Java中能不能强制中断线程的执行?
答:虽然提供了 stop 等函数,但是此函数不推荐使用,为什么因为这种暴力的方式,很危险,例如:下载图片5kb,只下载了4kb 等 我们可以使用interrupt来处理线程的停止,但是注意interrupt只是协作式的方式,并不能绝对保证中断,并不是抢占式的
-
TODO 【面试题】 如何让出当前线程的执行权?
答:yield方法,只在JDK某些实现才能看到,是让出执行权
-
TODO 【面试题】sleep,wait,到底那个函数才会 清除中断标记?
答:sleep在抛出异常的时候,捕获异常之前,就已经清除