目录
线程:
操作系统对资源调度的基本单位
进程:
操作系统对资源分配的基本单位
进程的调度
1,进程状态
就绪态 : 该进程已经准备好了,随时可以上cpu执行
阻塞态:该进程暂时无法上cpu执行
2,进程优先级
进程之间的调度不一定是"公平"的,有的要优先调度
3,进程上下文
上下文,就是描述了当前进程执行到哪里这样的"存档记录" 进程在离开CPU的时候就要把当前运行的中间结果"存档"等到下次进程回来CPU上,再恢复之前的"存档"从上次的结果继续往后执行
寄存器:最典型的作用就说保存当前进程执行的中间结果
存档 : 进程离开CPU就需要把这些寄存器的值保存到进程的结构体的上下文字段中
读档 : 进程下次回来CPU,再把PCB中的值给恢复到寄存器中
4,进程的进账信息
统计了每次进程在CPU上执行了多久了,可以作为调度的参考依据
进程间的通信:
在隔离性的状态下,找到一个公共区域,让两个进程借助这个公共区域来进行数据的交换
进程和线程的区别?
进程是操作系统进行资源分配的基本单位
线程是操作系统能进行资源调度的基本单位
进程之间具有独立性,一个进程崩了,不会影响到别的进程;同一个进程里的多个线程之间,一个线程挂了,可能会把整个进程带走
进程为什么这么重量?
主要就是体现在资源分配上 资源分配往往是一个耗时操作
比如系统要给进程分配一块内容
1)系统就需要遍历自己的空闲内存的表,找到一个大小差不多的空间进行分配
2)很多个进程都在问系统申请空间的时候,得一个一个来
线程为什么轻量?
约定,一个进程中可以包含多个线程,此时这多个线程每个线程都是一个独立可以调度执行的"执行流"(这些执行流之间本身就是并发的)同时这些线程共有同一份进程的系统资源)
(意味着,对于线程而言,系统资源已经分配好了的,创建线程就省下分配资源开销)
线程越多越好吗?
并不是的,因为线程是在进程里面来执行的,如果一个线程出异常了,此时就很容易把整个进程都带走了,其他线程也就被带走了
线程的创建和使用:
1,继承Thread 重写run的方式来创建线程
class Thread1 extends Thread{
public void run(){
System.out.println("执行支线程");
}
}
public class thread2 {
public static void main(String[] args) {
Thread t = new Thread1();
t.start();
System.out.println("执行主线程");
}
}
执行结果:
执行主线程
执行支线程
2,实现Runnable接口 重写run
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("执行支线程");
}
public static void main(String[] args) {
MyRunnable m = new MyRunnable();
Thread t = new Thread(m);
t.start();
System.out.println("执行main");
}
}
3,继承Thread 使用匿名内部类
public class Thread2 {
public static void main(String[] args) {
Thread t = new Thread() {
@Override
public void run(){
System.out.println("执行支线程");
}
};
t.start();
System.out.println("执行主线程");
}
}
4,实现Runnable 使用匿名内部类
public class Thread3 {
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("执行支线程");
}
});
t.start();
System.out.println("执行主线程");
}
}
5 ,使用lambda表达式,
本身就是一个匿名函数
写法:() -> { }
public class Thread4 {
public static void main(String[] args) {
Thread t = new Thread( () -> {
System.out.println("执行支线线程");
});
t.start();
System.out.println("执行主线程");
}
}
Thread.sleep(毫秒数)方法
使得当前线程进入休眠状态
start和run的区别?
start()是启动新线程 并且会自动调用run()方法
run()是特殊方法,是能被自动调用到的,是线程的入口方法
run()方法,重写了父类方法,如果随便写个方法只是普通的方法,没什么特殊含义
中断(终止)一个线程:
代码实现
public class Thread5 {
public static void main(String[] args) {
Thread t = new Thread( () ->
{
while (!Thread.currentThread().isInterrupted()){
System.out.println("执行支线程");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
t.interrupt();
}
}
线程安全:
线程不安全的原因:
1,抢占式执行
2,多个线程修改同一个变量
一个线程修改同一个变量=>安全
多个线程读取同一个变量 =>安全
多个线程修改不同变量===>安全
3,修改操作,不是原子的
4,内存可见性,引起的线程不安全
5,指令重排序,引起的线程不安全
如何解决线程不安全
- 使用锁机制:锁机制是一种用于控制多个线程对共享资源进行访问的机制
- 使用线程安全的容器
- 使用本地变量:线程本地变量是一种特殊的变量,它只能被同一个线程访问