1. 线程
线程指的是进程中的一个执行场景,也就是执行流程!进程和线程有什么区别?
每个进程就是一个应用程序,都会有独立的内存空间
同一个进程的线程共享其进程中的内存和资源2. 什么是进程?
一个进程就是一个应用程序 ,我们在操作系统每启动一个应用就会启动一个进程。
例如 QQ 腾讯会议.....3. 系统引入多进程有什么作用?
提高CPU的使用频率
进程和进程之间内存是独立的!!!4. 什么是线程?
线程是进程的一个执行场景。一个进程可以启动多个线程!!5. 进程引入多线程的作用是什么?
提高进程的使用率
线程和线程之间栈内存是独立的,堆内存和方法区内存共享,一个线程一个栈!!
6. 描述一下java程序的执行原理:
7. 线程的创建和启动
1.继承Thread类
2.实现 Runnable接口
1.继承Thread类
public class ThreadTest extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("我喜欢...");
}
}
}
public class Test {
public static void main(String[] args) {
ThreadTest threadTest=new ThreadTest();
threadTest.start();
Runnable r1=new RunnableTest();
Runnable r2=new RunnableTest2();
Thread t1=new Thread(r1);
Thread t2=new Thread(r2);
t1.start();
t2.start();
}
}
2.实现 Runnable接口
public class RunnableTest implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("我不喜欢");
}
}
}
public class Test {
public static void main(String[] args) {
ThreadTest threadTest=new ThreadTest();
threadTest.start();
Runnable r1=new RunnableTest();
Runnable r2=new RunnableTest2();
Thread t1=new Thread(r1);
Thread t2=new Thread(r2);
t1.start();
t2.start();
}
}
* @ClassName MyTask * @description: 这个是任务类,实现类Runnable 包含任务编号 id 每一个任务执行时间设计为0.2秒 * @datetime 2023年 03月 14日 11:20 * @version: 1.0*/
public class MyTask implements Runnable{
private int id;
public MyTask(int id) {
this.id = id;
}
@Override
public void run() {
String name=Thread.currentThread().getName();
System.out.println("线程"+name+"即将完成任务"+id);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程"+name+"完成了任务"+id);
}
@Override
public String toString() {
return "MyTask{" +
"id=" + id +
'}';
}
}
/** * @ClassName MyWork * @description: 线程类 需要继承 Thread 类 * * 一个属性保存线程名字, * * 一个集合 保存所有的任务 * @datetime 2023年 03月 14日 11:28 * @version: 1.0 */
public class MyWork extends Thread{
private String name;
private List<Runnable> tasks;//后续任务放到这个集合里面;
public MyWork(String name, List<Runnable> tasks) {
super(name);
this.tasks = tasks;
}
@Override
public void run() {
while(tasks.size()>0){
Runnable r=tasks.remove(0);
r.run();
}
}
}
/** * @author * @ClassName MyThreadPool * @description: * 自定义线程池类 * * 成员变量: * * 任务队列 集合 为了安全创建方式不一样 * * 核心线程数 * * 当前线程数 * * 最大线程数 * * 任务队列长度 * * * * 成员方法 * * 提交任务 * * 将任务添加到集合中,需要判断是否超出了任务总长度 * * 执行任务 * * 判断当前线程数量,决定创建核心线程还是非核心线程 * @datetime 2023年 03月 14日 11:41 * @version: 1.0 */
public class MyThreadPool {
//1.任务队列 集合 需要控制线程安全
private List<Runnable> tasks=Collections.synchronizedList(new ArrayList<>());
// 2.当前线程的数量
private int num;
//3.核心线程数量
private int corePoolSize;
//4. 最大线程数
private int maxSize;
//5. 任务队列的长度
private int worksize;
public MyThreadPool(int corePoolSize, int maxSize, int worksize) {
this.corePoolSize = corePoolSize;
this.maxSize = maxSize;
this.worksize = worksize;
}
public void submit(Runnable r){
if(tasks.size()>=worksize){
System.out.println("任务"+r+"被丢弃了");
}else {
tasks.add(r);
exexTask(r);//执行任务
}
}
public void exexTask(Runnable r){
if(num<corePoolSize){
new MyWork("核心线程"+num,tasks).start();
num++;
}else if(num<maxSize){
new MyWork("非核心线程"+num,tasks).start();
num++;
}else {
System.out.println("任务"+r+"被缓存了");
}}}
* @author * @ClassName MyTest * @description: 测试类 * * 创建线程池对象 * * 提交多个任务 * @datetime 2023年 03月 14日 15:16 * @version: 1.0 */
public class MyTest {
public static void main(String[] args) {
//创建线程池对象
MyThreadPool myThreadPool=new MyThreadPool(2,4,20);
//提交多个任务
for (int i = 0; i < 30; i++) {
MyTask myTask=new MyTask(i);
myThreadPool.submit(myTask);
}
}
}
总结:
第一步:先去创建任务类,属性一个id,作为一个任务的标志,也就是实现Runnable接口,重写run方法和toString方法,这样打印任务的时候,就是id,run方法里面去定义一个任务开始的标志,和任务完成的标志,更容易理解。
获取线程名字的语句: String name=Thread.currentThread().getName();
第二步:创建一个线程类MyThread,当线程池需要几个线程的时候,可以直接
new MyThread(name,List<Runnable>).start。这个线程类首先,要有线程名字属性和任务类的集合属性,用来存储任务的,也要有一个含参数的构造方法,super(name),调用父类的构造方法。重写run方法,里面要去获取任务集合的任务,采用remove方法,然后调用run方法。
第三步:创建一个线程工厂,含有一个含参构造方法和submit方法,一个创建线程的方法。
控制线程集合中任务的数量,当线程集合长度大于任务队列,任务将会被抛弃,否则tasks.add。然后执行exexTask,标记一个num,当第一个任务进来,创建线程,将tasks的引用地址传给线程类。这个exexTask会去判断任务的状态。
第四步:创建测试类,创建实例对象线程池,模拟任务,submit提交任务。
思考:明明任务被缓存了,后续线程还是能执行这些被缓存的任务呢?
主线程一直在执行tasks.add的操作,
等主线程执行完后,核心线程和非核心线程才会去运行,这个时候,MyWork里面的tasks.remove的指向的内存地址其实就是线程池的tasks的内存地址。只要不结束此次运行,他们两个类实际上一直在操作一个tasks。