进程和线程
进程的概念
- 进程就是计算机正在运行的一个独立的应用程序。
- 进程是一个动态的概念,当启动应用时,进程就产生了,当关闭应用的时候,进程就结束了,进程的生命周期就是使用该软件的整个过程。
线程的概念
- 线程是组成进程的基本单位,可以完成特定的功能,一个进程由一个或多个线程组成。
- 应用程序是静态的,进程和线程是动态的,有创建有销毁,存在是暂时的,不是永久的。
进程和线程的区别
- 进程在运行时拥有独立的内存空间,即每个进程所占用的内存空间都是独立的,互不干扰。
- 线程是共享空间的,但是每个线程的执行都是相互独立的,单独的线程是无法执行的,有进程来控制多个线程的执行。
多线程
多线程是提升程序性能非常重要的一种方式,必须掌握的技术。
使用多线程可以让程序充分利用CPU资源
概念
- 多线程是指在一个进程中,多个线程同时执行,这里说的同时执行并不是正在意义的同时执行,而是在同一时间段内进行交替执行。
- 系统会为每个线程分配CPU资源,在某个具体时间段内CPU资源会被一个线程占用,在不同时间段内有不同线程来占用CPU资源,所以多个线程还是在交替执行。
- 线程和任务:线程是抢占CPU资源的,任务是执行具体业务逻辑的,线程内部会包含一个任务,线程启动(start),当抢占到CPU资源后,任务开始执行(run)。
优点
- 系统资源得到更合理的利用
- 程序设计更加简洁
- 程序响应更快
缺点
- 需要更多的内存空间来支持多线程
- 多线程并发访问的情况可能会影响数据的准确性
- 数据被多线程共享,可能会出现死锁的情况
多线程代码演示
public static void main(String[] args) {
//两个线程交替执行
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0 ; i < 500 ; i ++){
System.out.println("一一一");
}
}
}).start();
for (int i = 0 ; i < 500 ; i ++){
System.out.println("二二二");
}
}
Java中线程的使用
两种方式:
-
继承Thread类
①创建自定义类并继承Thread类
②重写Thread类中的run方法 -
实现Runnable接口
①创建自定义类并实现Runnable接口
②实现run方法,编写该线程业务中的业务逻辑
两种方式的区别: -
MyThread,继承Thread类的方式,直接在类中重写run方法,使用的时候,直接实例化MyThread,执行start方法即可,因为Thread内存存在Runnable。
-
MyRunnable,实现Runnable接口的方法,在实现类中重写run方法,使用的时候,需要先创建Thread对象,并将MyRunnable注入到Thread中,Thread.start。
推荐使用第二种,降低耦合度。
代码实现
- 继承Thread类
public class Thread1 extends Thread{ //继承Thread类
@Override
public void run() { //重写run方法
for (int i = 0 ; i < 500 ; i ++){
System.out.println("---------------");
}
}
}
public class Thread2 extends Thread{ //继承Thread类
@Override
public void run() { //重写run方法
for (int i = 0 ; i < 500 ; i ++){
System.out.println("+++++++");
}
}
}
public class ThreadTest {
public static void main(String[] args) {
Thread1 thread1 = new Thread1(); //实例化
Thread2 thread2 = new Thread2();
thread1.start(); //调用start方法后会自动执行run方法
thread2.start();
thread2.run(); //不能直接调用run方法,否则线程间进行排队,不会进行资源抢占
thread1.run(); //等待上一个thread1的run方法执行后才开始执行
}
}
注意:不能直接通过run方法调用线程任务,因为run方法调用相当于普通对象的执行,不会抢占CPU资源。只有通过start方法才能开启线程,进而抢占CPU资源,当某个线程抢占到CPU资源后,会自动调用run方法。
- 实现runable接口
public class MyRunnable implements Runnable{ //实现接口
@Override
public void run() { //编写run方法
for (int i = 0 ; i < 500 ; i ++){
System.out.println("run-run-run");
}
}
}
public class MyRunnable2 implements Runnable{ //实现接口
@Override
public void run() { //编写run方法
for (int i = 0 ; i < 500 ; i ++){
System.out.println("able-able-able");
}
}
}
public class ThreadTest {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable(); //实例化一个Runnable
MyRunnable2 myRunnable2 = new MyRunnable2();
new Thread(myRunnable).start(); //创建一个子线程,注入runnable
new Thread(myRunnable2).start();
Thread thread1 = new Thread(myRunnable);
Thread thread2 = new Thread(myRunnable2) ;
thread1.start();
thread2.start();
}
}
线程状态
线程有5中状态,在特定情况下,线程可以在不同状态之间切换。
- 创建状态:实例化一个新的线程对象,还未启动。
Thread1 thread1 = new Thread1(); //创建状态
MyRunnable myRunnable = new MyRunnable(); //实例化一个Runnable,不是线程
Thread thread1 = new Thread(myRunnable); //该步骤执行后才是创建状态
- 就绪状态:创建好的线程对象调用start方法后完成启动,进入线程池等待抢占CPU资源。
thread1.start(); //执行start方法启动后,进入就绪状态
- 运行状态:线程获取CPU资源,在一定时间内执行任务。
- 阻塞状态:正在运行的线程暂停执行任务,释放所占用的CPU资源,并在接触阻塞后,不可以直接回到运行状态,而是重新进入就绪状态,等待获取CPU资源。
- 终止状态:线程运行完毕或因为异常导致该线程终止运行。