一、什么是程序
程序是指实现某种特定的目标或问题而用计算机语言编写的命令的集合
二、什么是进程 (process)
进程是指程序的一次执行过程,当程序运行结束时,进程结束
三、什么是线程
线程是进程中独立的执行单元,它们相互不影响,线程消耗的资源很少,可以被称作轻量级的进程,但线程并不是进程
四、线程与进程的关系
①进程存在于线程之中,一个进程至少包含一个线程,而一个线程必须在进程内运行
②同一进程中的线程是抢占式的独立运行,抢占CPU资源
③进程中的线程结束,进程也结束;如果进程中没有可执行的线程,进程也结束
④线程有独立的执行堆栈、程序计数器和局部变量,没有独立的存储空间,而是和所属进程中的其它线程共享存储空间
⑤操作系统将进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位,由于线程比进程更小,基本上不拥有系统资源,故对它的调度所付出的开销就会小得多,能更高效的提高系统多个程序间并发执行的速度。 |
五、如何创建线程
第一种方式:继承java.lang.Thread类,重写run方法;
class TimeThread extends Thread{
@Override
public void run() {
for (int i=0;i<5;i++) {
System.out.println("计数2"+":"+i);
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
第二种方式:实现java.lang.Runnable接口,实现run抽象方法
class CountThread implements Runnable{//接口里面没有start()方法,因此不可以使用对象调用start()方法
@Override
public void run() {
for (int i = 0; ; i++) {
System.out.println("计数1"+i);
}
}
}
创建线程对象
public class Test {
public static void main(String[] args) {
new Thread(new CountThread()).start();//Thread是线程,new CountThread()只是一个普通的对象
new TimeThread().start();//使用new关键字代表新建了一个线程,调用start()方法,代表进入就绪状态,拥有抢占CPU的资格
}
}
六、 线程生命周期
线程的什么周期分为新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead),如下图所示
新建(New):代表新建了一个线程对象
就绪(Runnable):调用start()方法,线程拥有竞争CPU的资格,而不是真正的运行
运行:就绪状态的线程获取了CPU使用权,执行程序代码
阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种
死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
注意:使用new关键字代表新建了一个线程,调用start()方法,代表进入就绪状态,拥有抢占CPU的资格,而不是立即进入了运行状态
七、线程池
如果程序在短时间内有大量的线程任务,不断的创建和销毁线程,非常浪费时间,如果不加限制的创建和启动线程,极有可能导致内存溢出,最终使程序崩溃;
而线程池里的每一个线程任务结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用,因而借助线程池可以提高程序的执行效率;
线程池中线程数量是一定的,可以有效避免出现内存溢出。
示例:
public class Test {
public static void main(String[] args) {
/**
* 线程执行过程分析:由于线程池里面只有两个线程,因此首先会有两个线程先执行,他们的执行同样的遵循抢占式运行的特点,
* 这两个线程谁先结束,就会把线程放回线程池,处于空闲的状态,此时第三的对象得到该线程,与其他的线程争夺CPU的执行权
*/
//ExecutorService 表示一个线程池
ExecutorService executorService = Executors.newFixedThreadPool(2);//创建一个可重用的、具有固定线程数的线程池;该线程池有2个线程
//submit(Runnable task):提交Runable接口实现类实例;Runnable task:创建Runable接口实现类实例,由于Runable是函数式接口,因此可以使用Lambda表达式
executorService.submit(()->{
for (int i = 0;i<5; i++) {
System.out.println("计数1"+":"+i);
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
executorService.submit(()->{
for (int i = 0;i<5; i++) {
System.out.println("计数2"+":"+i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
executorService.submit(()->{
for (int i = 0;i<5; i++) {
System.out.println("计数3"+":"+i);
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
executorService.shutdown();//关闭线程池
}
}