1.进程
进程是操作系统的一个任务(应用程序运行在一个进程中)。
进程是含有某些资源的内存区域。进程中会有一个线程或者是多个线程
举例说明:OS(操作系统)会打开多个应用程序,如可以打开视频软件,音频软件,qq等。
2.线程
线程是进程中的一个顺序执行流(顺序执行流是有程序启动入口,程序逻辑和程序结束出口)。
线程是应用程序中的一个任务(此任务完成了一个功能)。
举例说明:视频软件打开后,会有缓冲功能,播放功能。
3.进程和线程的区别:
进程是针对于OS级别来说的一个任务。线程是针对于app级别来说的一个任务。
线程有自己独立的堆栈空间,线程属于进程中的一部分,多个线程可以共享进程的内存空间。
线程之间的切换比较轻负荷。线程又叫轻负荷进程。
4.并发
在计算机中,宏观上,如果打开多个app,发现可以"同时运行",其实在微观上是断断续续的。
cpu会将一段时间划分成无数微小的时间片段,然后把时间片段尽可能的平均随机的分配给某一个线程(其他线程处于等待状态)进行微观的,肉眼感知不到的间歇性运行。这就是并发。实际上并不是我们所说的"同时进行"。
并发可以提高效率。
5.线程的生命状态
新建状态:
使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。
就绪状态:
当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。
运行状态:
如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。
阻塞状态:
如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:
等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。
同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。
其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。
死亡状态:
一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。
6.线程的创建
1)继承Thread类,重写run方法(run方法的作用就是写任务逻辑代码)
线程启动时,调用start(),不能调用run()。
2)实现Runnable接口,重写Run方法
还要把Runnable的子类型传入Thread对象中,由Thread对象负责启动线程
7.线程的常用API
getName():获取线程的名称(系统分配Thread-X)
getId():获取线程的唯一标识符
currentThread():静态方法,获取当前线程对象
sleep(long time):静态方法,使线程进入阻塞状态多少毫米
interrupt():打断当前的阻塞状态下的线程
yield():使线程回到Runnable状态,让出当前的时间片段
join():可以使线程处于同步状态(一个线程需要等待另一个线程完成后才能继续运行)
8.线程的优先级
线程的优先级:
线程是有优先级的,由1-10优先级越来越高。
理论上,优先级高的线程获取cpu的时间片段多。
getPriority():
设置优先级,一定要在线程启动前设置才会生效。
9.线程安全问题
当多个线程同时访问某一处资源时,会发生线程安全问题。
这类资源可能是
1)静态资源
2)实例属性
怎么处理这种现象呢?我们应该让多线程异步访问这个资源变成同步访问这个资源。
异步:多个线程“同时进行”,各干各的。
同步:多个线程要按照顺序,一个访问完,下一个才能访问。
锁机制:关键字synchronized(同步),java语言可以为某一块代码提供一个内置锁。
格式:
synchronized(锁对象){
//代码块
}
1)可以修饰方法,将这个方法上锁
锁对象
静态方法:类名.class
动态方法:对象
2)修改代码块
synchronized(锁对象){
//代码块
}
锁:java的任何对象都可以作为锁对象的。但是不建议必须保证多个线程使用的是同一个锁。
如果锁不是用一个,那么就解决不了线程安全问题。
可以对方法进行直接加锁机制,有锁,锁是类对象(获取类对象的方法:类名.class,类对象是唯一的)。
在使用锁机制时,要注意效率。锁入的代码块越少效率越高。静态方法和动态方法在使用锁机制时,不互斥(谁也不会影响谁)。静态方法的锁对象是类对象,动态方法的锁是对象。
wait()/notify()/notifyAll():作用是协调多线程的工作。
方法都是锁对象的。
obj.wait():告诉当前线程需要等待
obj.notify():当前线程通告锁对象通知等待的线程
obj.notifyAll():通过锁对象通知所有等待的线程
关系如下:线程A要等待线程B运行完才可以运行。
线程A中要使用 锁对象.wait() 表示等待(让出cpu时间片段)
线程B运行完时,需要使用 锁对象.notify() 通知线程A,可以运行了。
10.线程池
java中提供了一个类型Executors,此类型提供了多种创建线程池的方法。
线程池就是含有多个线程的一个对象。
当服务器上的一个线程结束或者是线程之间的切换都会频繁的消耗系统内存。
我们可以在创建一定数量的线程后,不结束这些线程,当任务执行完后,让这些线程继续执行其他的任务,大大减少了内存消耗。