线程基本概念详解
本⽂只是粗略的讲解了⼀下有关线程的问题,讲的并不是⾮常的完全。还有很多可以写,但是万般头绪慢慢来,刚开始写只是列了⼀个⼤纲,然后越写越多,发现打不住头了,只写了⼀些线程的概念和实现的⽅法,线程的作⽤什么的。匿名内部线程什么的。写的时候在⽹上也找了部分⾃⼰感觉好的解释和例⼦。后⾯在开章写线程的同步,异步等问题。本⽂如果发现有问题,欢迎留⾔指正。感谢!
讲线程之前先讲⼀个进程的概念:进程(Process)是计算机中的程序关于某数据集合上的⼀次运⾏活动,是系统进⾏资源分配和 调度的基本单位,是操作系统结构的基础。简单点说就是 ⼀个应⽤程序可以理解成就是⼀个进程。
⼀个进程包含⽆数个线程,每个线程分别实现该应⽤程序的不同功能。下⾯就从最基本的线程讲起。
什么是线程?
1. 线程是进程的⼀个实体,是CPU调度和分派的基本单位,它是⽐进程更⼩的能独⽴运⾏的基本单位。线程⾃⼰基本上不拥有系
统资源,只拥有⼀点在运⾏中必不可少的资源(如程序计数器,⼀组寄存器和栈),但是它可与同属⼀个进程的其他的线程共享进程所拥有的全部资源。
2. ⼀个线程可以创建和撤消另⼀个线程,同⼀进程中的多个线程之间可以并发执⾏。由于线程之间的相互制约,致使线程在运⾏
中呈现出间断性。线程也有、和三种基本状态。
3. 每⼀个程序都⾄少有⼀个线程,若程序只有⼀个线程,那就是程序本⾝。
什么是多线程(Multithreading)?
多线程就是为了使得多个线程并⾏的⼯作以完成多项任务,以提⾼系统的效率。线程是在同⼀时间需要完成多项任务的时候被实现的。
什么是并⾏,并发和⾼并发?
1.并⾏简单点说:同时运⾏多条线程,就是并⾏ 例如:两个任务同时运⾏,就是甲任务进⾏的同时,⼄任务也在进⾏。(需要多核CPU,现在的电脑基本上都⽀持。)
描写鸟的诗句2.并发 :在操作系统中,是指⼀个时间段中有⼏个程序都处于已启动运⾏到运⾏完毕之间,且这⼏个程序都是在同⼀个处理机上运⾏,但任⼀个时刻点上只有⼀个程序在处理机上运⾏。
3.⾼并发简单点说:就是在同⼀时刻不同⽤户访问同⼀资源的问题,专业⼀点的说法就是在同⼀时刻有多个线程访问了同⼀个数据资源。
Java程序运⾏原理:
1. Java命令会启动java虚拟机(JVM),等于启动了⼀个应⽤程序,也就是启动了⼀个进程。
2. 该进程会⾃动启动⼀个 “主线程” ,然后主线程去调⽤某个类的 main ⽅法
3. ⼀个应⽤程序有且只有⼀个主线程,程序员不能New主线程,可以New⼦线程。
JVM启动的是多线程吗?
JVM启动⾄少启动了垃圾回收线程和主线程,所以是多线程的。
main⽅法的代码执⾏的位置就是在主线程(路径)
⼀个进程有多个线程
finalize()这个⽅法在⼦线程(垃圾回收线程)执⾏
/*JVM的启动是多线程的吗?*/
public class Demo01 {
public static void main(String[] args) {
System.out.println("AAAAA");
System.out.println("BBBBB");
幸福的开关
System.out.println("CCCCC");
System.out.println("DDDDD");
//打印线程名称
System.out.println(Thread.currentThread());//主线程
for(int i = 0;i<2;i++){
new Student();
<();//启动垃圾回收
}
}
}
class Student{
//被垃圾回收器回收时,会调⽤
//对象从内存释放时,会调⽤
@Override
protected void finalize() throws Throwable {
// TODO Auto-generated method stub
System.out.println("student 被回收了...");
//打印线程名称
System.out.println(Thread.currentThread());//⼦线程
}
}
什么时候使⽤多线程?
当⼀个进程中多个任务可以并⾏执⾏时,可以为每个任务启动⼀个线程。
线程适⽤范围:
1. 服务器中的⽂件管理或通信控制
2. 前后台处理
3. 异步处理
线程的作⽤:(⼀般通过同步,异步,线程池来实现)
有计划,有顺序的执⾏程序的各项功能,优化程序的执⾏过程,减少死机的可能。(开单章再说)线程的实现⽅法:(具体实现⽅法在下⾯)
1. 继承Thread类,并重写run函数
2. 实现Runnable接⼝,并重写run函数
原因: 因为java是单继承的,在某些情况下⼀个类可能已经继承了某个⽗类,这时在⽤继承Thread类⽅法来创建线程显然不可能java 设计者们提供了另外⼀个⽅式创建线程,就是通过实现Runnable接⼝来创建线程。(也有⼈说线程的实现⽅法是4个,另外2种为:实现Callable接⼝通过FutureTask包装器来创建Thread线程、使⽤ExecutorService、Callable、Future实现有返回结果的多线程。)
什么是线程池?
线程池是指在初始化⼀个多线程应⽤程序过程中创建⼀个线程集合,然后在需要执⾏新的任务时重⽤这些线程⽽不是新建⼀个线程。线程池中线程的数量通常完全取决于可⽤内存数量和应⽤程序的需求。然⽽,增加可⽤线程数量是可能的。线程池中的每个线程都有被分配⼀个任务,⼀旦任务已经完成了,线程回到池⼦中并等待下⼀次分配任务。
为什么需要线程池?
线程池改进了⼀个应⽤程序的响应时间。由于线程池中的线程已经准备好且等待被分配任务,应⽤程序可以直接拿来使⽤⽽不⽤新建⼀个线程。
线程池节省了CLR 为每个短⽣存周期任务创建⼀个完整的线程的开销并可以在任务完成后回收资源。
线程池根据当前在系统中运⾏的进程来优化线程时间⽚。
线程池允许我们开启多个任务⽽不⽤为每个线程设置属性。
线程池允许我们为正在执⾏的任务的程序参数传递⼀个包含状态信息的对象引⽤。
线程池可以⽤来解决处理⼀个特定请求最⼤线程数量限制问题。
影响设计⼀个多线程应⽤程序的因素有:
1. ⼀个应⽤程序的响应时间。
2. 线程管理资源的分配。
3. 资源共享。
4. 线程同步。
===========线程的实现⽅法============
⽅式⼀、继承Thread
使⽤步骤:
1. 定义类继承Thread
2. 重写run⽅法
胃灵合剂3. 把新线程要做的事写在run⽅法中
4. 创建线程对象
5. 开启新线程, 内部会⾃动执⾏run⽅法
/*主线程,程序员不能创建,程序员只能创建⼦线程*/
//1.创建⼦线程对象
MyThread t1 = new MyThread();
/**不能通过下⾯的⽅式来执⾏任务
* 因为这种⽅式中的任务是在主线程执⾏的*/
//t1.run();
//2.正确的执⾏任务的⽅式,调⽤start,内部会开启新线程,调⽤run⽅法
t1.start();
//3.再创建⼦线程
MyThread t2 = new MyThread();
t2.start();
//4.循环创建⼦线程
for(int i=0;i<10;i++){
MyThread th = new MyThread();
th.start();
}
}
}
处臵class MyThread extends Thread{
@Override
public void run() {
System.out.println("银⾏信⽤卡还款短信任务..." + Thread.currentThread());
描写天气好的词语
System.out.println("线程名称" + Name());
}
}
⽅式⼆、实现Runnable接⼝
实现步骤:
谢谢你的陪伴定义类实现Runnable接⼝
实现run⽅法
把新线程要做的事写在run⽅法中
创建⾃定义的Runnable的⼦类对象,创建Thread对象传⼊Runnable
调⽤start()开启新线程, 内部会⾃动调⽤Runnable的run()⽅法
/
* 线程实现的⽅式 (2) - 定义类实现Runnable接⼝
//1.创建runable对象
BankTask task = new BankTask();
//2.创建Thread对象
Thread t1 = new Thread(task);
//3.启动线程
t1.start();
//4.再开启2个线程
Thread t2 = new Thread(task);
t2.start();
Thread t3 = new Thread(task);
t3.start();
}
}
class BankTask implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("银⾏储蓄卡⾃动结算利息任务..." + Thread.currentThread());
//System.out.println("线程名称:" + Name());
System.out.println("线程名称:" +Thread.currentThread().getName());
}
}
两种⽅式的区别
冷漠的全部歌曲区别:
继承Thread : 由于⼦类重写了Thread类的run(), 当调⽤start()时直接找⼦类的run()⽅法
实现Runnable : 构造函数中传⼊了Runnable的引⽤, 有个成员变量记住了它, 调⽤run()⽅法时内部判断成员变量Runnable的引⽤是否为空。
人类的起源和进化
继承Thread
好处是:可以直接使⽤Thread类中的⽅法,代码简单
弊端是:如果已经有了⽗类,就不能⽤这种⽅法(Java只能单继承)