进程
进程就是正在运行的程序,它会占用对应的内存区域,由CPU进行执行与计算
特点
独立性
进程是系统中独立存在的实体,它可以拥有自己独立的资源,每个进程都拥有自己私有的地址空间,在没有经过进程本身允许的情况下,一个用户进程不可以直接访问其他进程的地址空间
动态性
进程与程序的区别在于,程序只是一个静态的指令集合,而进程是一个正在系统中活动的指令集合,程序加入了时间的概念以后,称为进程,具有自己的生命周期和各种不同的状态,这些概念都是程序所不具备的.
并发性
多个进程可以在单个处理器CPU上并发执行,多个进程之间不会互相影响.
线程
线程是操作系统OS能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位.
一个进程可以开启多个线程,其中有一个主线程来调用本进程中的其他线程。
多线程可以让同一个进程同时并发处理多个任务,相当于扩展了进程的功能 。
一个操作系统中可以有多个进程,一个进程中可以包含一个或多个线程。
多线程特点
随机性 一个CPU【单核】只能执行一个进程中的一个线程
CPU分时调度
- FCFS(First Come First Service 先来先服务算法)
- SJS(Short Job Service短服务算法)
线程状态
就绪(可运行)状态:线程已经准备好运行,只要获得CPU,就可立即执行
执行(运行)状态:线程已经获得CPU,其程序正在运行的状态
阻塞状态:正在运行的线程由于某些事件(I/O请求等)暂时无法执行的状态,即线程执行阻塞
串行:同一时刻一个CUP只能 处理一件事
并行:同一时刻多个CUP处理多个事件
时间片:CPU分配给各个线程的一个时间端,即线程被允许执行的时间,当CPU被分配给另一个线程时,当前线程挂起,如果线程在片时间完成之前阻塞或结束,CPU当即切换
多线程实现方式
一,继承
- 自定义一个类extends Thread
- 重写run()方法
- 创建多个线程对象
- 线程对象调用start(),以多线程的方式启动
public class TestThread1 {
public static void main(String[] args) {
TicketThread t1 = new TicketThread();
TicketThread t2 = new TicketThread();
TicketThread t3 = new TicketThread();
TicketThread t4 = new TicketThread();
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class TicketThread extends Thread{
static int tickets = 100;
static Object o = new Object();
@Override
public void run(){
while (true){
// synchronized (TicketThread.class) {
synchronized (o) {
if (tickets > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(getName() + "=" + tickets--);
}
if (tickets <= 0) break;
}
}
}
}
二、实现
- 自定义一个类实现Runnable接口
- 添加接口中未实现的抽象方法run()
- .创建Runnable接口的实现类【也就是自定义类】对象,作为目标业务对象
- .创建线程对象,通过线程对象调用start(),把线程对象加入就绪队列,Thread.currentThread().getName()获取线程名称
public class TestRunnable {
public static void main(String[] args) {
TickectsRunnable target = new TickectsRunnable();
Thread t1 = new Thread(target);
Thread t2 = new Thread(target);
Thread t3 = new Thread(target);
Thread t4 = new Thread(target);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class TickectsRunnable implements Runnable{
int tickets = 100;
Object o = new Object();
@Override
public void run() {
while (true){
synchronized (o) {
// synchronized (TickectsRunnable.class) {
if (tickets > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName() + "=" + tickets--);
}
if (tickets <= 0) break;
}
}
}
}
实现方式有点:
- 耦合性不强,没有继承,后续仍然可以继承
- 采用实现接口的方式,后续仍然可以实现其他接口
- 可以给所有线程对象统一业务,业务保持一致
可能出现线程安全问题情况 :多线程程序 + 有共享数据 + 多条语句操作共享数据
同步:每次只有一个线程独占资源,排队,效率低但是安全,synchronized也被称作同步关键字
异步:是多个线程抢占资源的效果,不排队,效率高,但数据不安全
线程池
- Executors是用来创建线程池的工具类
- 常用方法: newFixedThreadPool(int)用于创建指定数量的线程池对象 创建出来的线程池对象ExecutorService用来存储线程的池子,负责新建,关闭、启动,execute(Runnable任务对象) 把任务丢到线程池,newCachedThreadPool() 足够多的线程,使任务不必等待,newSingleThreadExecutor() 只有一个线程的线程池
- Executors工具类创建一个最多具有5个线程池对象
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestRunnable {
public static void main(String[] args) {
TickectsRunnable target = new TickectsRunnable();
/*Executors是用来创建线程池的工具类,它的常用方法:
newFixedThreadPool(int)用于创建指定数量的线程池对象
创建出来的线程池对象ExecutorService用来存储线程的池子,负责新建,关闭、启动---*/
//使用Executors工具类创建一个最多具有5个线程池对象
ExecutorService pool = Executors.newFixedThreadPool(5);
for(int i = 0;i < 5;i++){
//excute()让线程池安排线程执行业务,每次调用都会安排一个线程对象加入就绪队列
pool.execute(target);
}
}
}
class TickectsRunnable implements Runnable{
int tickets = 100;
Object o = new Object();
@Override
public void run() {
while (true){
synchronized (o) {
// synchronized (TickectsRunnable.class) {
if (tickets > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName() + "=" + tickets--);
}
if (tickets <= 0) break;
}
}
}
}
锁
- 使用锁的前提:同步需要两个或者两个以上的线程,多个线程间必须使用同一个锁
- 如果是继承方式,锁对象要设置成静态,如果实现方式,锁对象无需设置静态
- 锁对象可以是新建一个对象,不限制类型,唯一即可,也可用类名.class的方式
synchronized (锁对象){
需要同步的代码(也就是可能出现问题的操作共享数据的多条语句);
}synchronized同步关键字可以用来修饰代码块,称为同步代码块,使用的锁对象类型任意,但注意:必须唯一!
synchronized同步关键字可以用来修饰方法,称为同步方法