线程基础

线程的基础概念

1. CPU核心和线程数的关系

​ 核心数:线程数=1:1 ;使用了超线程技术后—> 1:2 ;简单的说就是一个cpu只能同时处理一个线程.

2. CPU时间片轮转机制

​ 又称RR调度,会导致上下文切换.

这里讲下cpu时间片轮转机制的概念:

​ 时间片轮转法(Round-Robin,RR)主要用于分时系统中的进程调度。为了实现轮转调度, 系统把所有就绪进程按先入先出的原则排成一个队列。新来的进程加到就绪队列末尾。每当执行进程调度时,进程调度程序总是选出就绪队列的队首进程,让它在CPU上运行一个时间片的时间。时间片是一个小的时间单位,通常为10~100ms数量级。当进程用完分给它的时间片后,系统的计时器发出时钟中断,调度程序便停止该进程的运行,把它放入就绪队列的末尾;然后,把CPU分给就绪队列的队首进程,同样也让它运行一个时间片,如此往复。

3. 什么是进程和线程

​ 进程:程序运行资源分配的最小单位,进程内部有多个线程,会共享这个进程的资源

​ 线程:CPU调度的最小单位,必须依赖进程而存在。

4. 澄清并行和并发

​ 并行:同一时刻,可以同时处理事情的能力

​ 并发:在单位时间内可以处理事情的能力

总结一下:

​ 并行指的是一段时间,比如从中午的11点到12点能处理多少线程.

​ 并发指的是同一时刻,比如双十一的00:00这一时刻能处理多少线程.

5. 高并发编程

​ 好处:充分利用cpu的资源、加快用户响应的时间,程序模块化,异步化

​ 问题:

​ 线程共享资源,存在冲突;

​ 容易导致死锁;

​ 启用太多的线程,就有搞垮机器的可能

Java中的线程

1. Java天生就是多线程的

​ 我们看下下面这个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class OnlyMain {

public static void main(String[] args) {
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false, false);

for(ThreadInfo threadInfo : threadInfos){
System.out.println(threadInfo.getThreadId()+":"+threadInfo.getThreadName());
}
}

}
//执行了一次main方法控制台输出如下
=============================================================================
6:Monitor Ctrl-Break
5:Attach Listener
4:Signal Dispatcher
3:Finalizer
2:Reference Handler
1:main

​ 我们看到执行一个main方法,并不是只执行了main这一个线程,实际上有6个线程参与了main方法的执行.

2. 实现线程的三个方法

​ 我们知道实现线程的方法有继承Thread类和实现runable或者callable接口,为啥可以继承一个类就可以完成的事情,还有要多此一举在写一个runable接口呢,因为Java是单继承了,它只可以继承一个类,但是可以实现多个接口.

​ 通常日常编程中可能Thread和runable用的比较多,callable方法用的比较少,实现callable接口的线程是可以带有返回值得,这里简单写下callable接口具体的实现代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class TestA {
//callable接口可以定义一个泛型
private static class UseCall implements Callable<String>{
@Override
public String call() throws Exception {
System.out.println("i am implements Callable");
return "UseCall";
}
}

public static void main(String[] args) throws ExecutionException, InterruptedException {
UseCall useCall = new UseCall();
FutureTask<String> futureTask = new FutureTask<>(useCall);
new Thread(futureTask).start();
System.out.println(futureTask.get());
}

}
=================================运行结果=====================================
i am implements Callable
UseCall
3.让Java的线程安全的停止工作

​ stop()停止方法、resume()继续执行方法、suspend()挂起方法.
这三个方法在早期的时候是有的,但现在已被废弃。因为这些方法过于强势,它强行终止一个线程,它是无法保证线程的资源能正常被释放,即线程不会释放资源。(不推荐使用)

​ java线程是协作式,而非抢占式.

​ 调用一个线程的interrupt() 方法中断一个线程,并不是强行关闭这个线程,只是跟这个线程打个招呼,将线程的中断标志位置为true,线程是否中断,由线程本身决定。如果线程通过wait()进入阻塞状态,此时通过interrupt()中断该线程;调用interrupt()会立即将线程的中断标记设为“true”,但是由于线程处于阻塞状态,所以该“中断标记”会立即被清除为“false”,同时,会产生一个InterruptedException的异常。

​ isInterrupted() 判定当前线程是否处于中断状态。

​ static方法interrupted() 判定当前线程是否处于中断状态,同时中断标志位改为false。(该方法调用后会将中断标示位清除,即重新设置为false,如果连续两次调用该方法,则第二次调用将返回 false。)。

​ 对于上面方法的一些概念和使用方法以及其中的坑可以看下LZing_的博客,总结的通俗易懂.

​ 关于interrupt()的详细使用方法可以看下多线程interrupt()和线程终止方式

线程多认识一点点

1.线程的状态和常用方法:

​ 线程只有5种状态。整个生命周期就是这几种状态的切换。

​ run()和start() :run方法就是普通对象的普通方法,只有调用了start()后,Java才会将线程对象和操作系统中实际的线程进行映射,再来执行run方法。

​ yield() :让出cpu的执行权,将线程从运行转到可运行状态,但是下个时间片,该线程依然有可能被再次选中运行。

2. 线程的优先级

​ 取值为1~10,缺省为5,但线程的优先级不可靠,不建议作为线程开发时候的手段

3. 守护线程

​ 和主线程是共死的,比如垃圾回收线程等等.

子线程执行完毕主线程也执行完毕.就算有finally{}也不一定会执行.下面举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class TestB {

private static class UseRunable implements Runnable{

@Override
public void run() {
String name = Thread.currentThread().getName();
while (!Thread.currentThread().isInterrupted()){
System.out.println(name + "is run");
}
}
}


public static void main(String[] args) throws ExecutionException, InterruptedException {
UseRunable useRunable = new UseRunable();
Thread endthread = new Thread(useRunable,"endthread");
endthread.setDaemon(true);
endthread.start();
Thread.sleep(5);
}
}


=======================================result================================
endthreadis run
endthreadis run
endthreadis run
endthreadis run
endthreadis run
endthreadis run
endthreadis run

说明:endthread.setDaemon(true)是将endthread线程设置为守护线程. 主线程main执行结束,endthread作为守护线程也会执行结束.

最后更新: 2019年06月19日 18:01

原始链接: https://coleflower.github.io/2019/06/19/了解线程(第一篇)/

× 请我吃糖~
打赏二维码