一、相关慨念
1.1、cpu核心数和线程的关系
一般情况下cpu的核心数等于线程数,如8核的cpu支持8个线程同时运行,在intel引入超线程技术以后,cpu核心数:线程数等于1:2的关系。
一般情况下,核心数:线程数=1:1;使用了超线程技术后 1:2
1.2、cpu时间片轮转机制
在开发中体会不到有几个线程存在,这是因为存在cpu时间片轮转机制(RR调度),即给每一个进程分配一个时间段,这个时间段就称为进程的时间片,进程允许运行的时间,如果到了这个时间片允许结束的时候进程还在运行,操作系统就会把分配给这个进程的cpu剥夺分配给另外一个进程;如果进程在这个时间片还没用完之前就阻塞或跑完了,那么cpu就会进行一个切换。
1.3、什么是进程和线程
进程:程序运行资源分配的最小单位;一个进程内部有多个线程,线程会共享这个进程的资源。
线程:cpu调度的最小单位,必须依赖进程而存在。线程自己是不拥有系统资源的,进程申请资源,给线程用,任何进程的运行都会必须创建一个线程。
并行和并发
并行:同一时刻,可以同时处理事情的能力。
并发:与单位时间相关,在单位时间内可以处理事情的能力。
高并发编程的意义,好处和注意事项
可以充分利用cpu资源;
可以充分加快响应用户的时间。
注意事项:
线程之间会共享进程的资源,有可能存在着冲突;
多线程控制不好还会出现死锁问题。
线程数太多,操作系统需要为这些线程分配资源,可能造成死机,搞垮机器。
二、java线程
2.1、创建线程的方式有哪些
继承Thread类,重写Thread的run()方法,将线程运行的逻辑放在其中
实现Runnable接口,实例化Thread类
实现Callable接口,实例化Thread类
package com.test;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class DemoTest {
//创建线程的三种方式
//继承Thread
//实现runnable接口
//实现callable接口
/**
* 继承 Thrad 类,重写run方法
* java单继承,继承Thrad类后就无法继承其他类了
*/
private static class UseThread extends Thread{
public void run() {
System.out.println("I am implements Thread");
}
}
/**
* 实现 Runnable 接口,重写run方法
* java可以实现多个接口
*/
private static class UseRunnable implements Runnable{
@Override
public void run() {
System.out.println("I am implements Runnable");
}
}
/**
* 实现 Callable 接口,重写run方法
* 线程执行完后返回String
*/
private static class UseCallable implements Callable<String>{
@Override
public String call() throws Exception {
System.out.println("I am implements Callable");
return "CallableResult";
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
//运行Thread线程
UseThread useThread = new UseThread();
useThread.start();
/**
*
* 运行Runnable线程;
* 需要实例化Thread类
*/
UseRunnable runnable = new UseRunnable();
new Thread(runnable).start();
/**
* 运行Callable线程,并返回结果,
* 实例化FutureTask对象,它实现了Runnable接口,所以可以把它递交给Thread去实例化。
* 需要实例化Thread类
*/
UseCallable useCallable = new UseCallable();
FutureTask<String> futureTask = new FutureTask<>(useCallable);
new Thread(futureTask).start();
String result = futureTask.get();//拿到Callable返回值
System.out.println("Callable返回结果:" + result);
/**
* 虚拟机线程管理接口,监控线程信息。
* 因为运行的时间比较短,gc还没来得运行,所以看不到gc线程。
*
* [6] Monitor Ctrl-Break
* [5] Attach Listener 负责获取当前程序运行的相关的各种信息,包括内存映像、线程栈、类信息的统计、系统属性
* [4] Signal Dispatcher 专门分发处理发送给虚拟机信号的线程
* [3] Finalizer 调用Finalizer方法得的线程
* [2] Reference Handler 用来清除应用的线程
* [1] main main线程
*/
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false,false);
for(ThreadInfo threadInfo:threadInfos){
System.out.println("[" + threadInfo.getThreadId() + "] " + threadInfo.getThreadName());
}
}
}
结果:
I am implements Thread
I am implements Runnable
I am implements Callable
Callable返回结果:CallableResult
[6] Monitor Ctrl-Break
[5] Attach Listener
[4] Signal Dispatcher
[3] Finalizer
[2] Reference Handler
[1] main
2.2、怎么样才能让java里的线程安全停止工作
stop()还是interrupt()、isInterrupted()、static方法interrupted(),深入理解这些方法。
stop():被废弃、不建议使用的方法,过于强势,强行终止一个线程,无法保证线程占有的资源正常释放,从而导致不可知的问题。
resumer()或suspend()挂起:被废弃、不建议使用的方法,调用后线程不会释放资源;线程挂起后占着资源,这时候有其他线程想拿这个资源,拿不到,很容易引起死锁问题。
建议使用interrupt()、isInterrupted()、static方法interrupted()来终止线程。
interrupt():中断一个线程,并不是强行关闭这个线程,只是跟这个线程打个招呼,将线程的中断标志位设置为true,线程是否中断,由线程本身决定。
isInterrupted():判断当前线程释放处于中断状态。
static方法Thread.interrupted():判断当前线程释放处于中断状态。与isInterrupted()区别:当我们调用了Thread.interrupted(),它会中断标志位改为false
2.3