线程
**程序:**是一个指令的集合。
**进程:**正在执行的程序。是一个动态的概念。
- 进程是程序的一次动态执行过程,占用特定的地址空间。
- 每个进程都是独立的,又三部分组成:cpu、data、code。
- 缺点:内存浪费,cpu有着不小的负担
**线程:**是进程中的一个“单一的连续控制流程”
- 线程又被称为轻量级的进程。
- 一个进程可以拥有多个并行的线程。
- 一个进程中的线程共享相同的内存单元、内存地址空间。可以访问相同的变量和对象,而且它们从同一堆中分配对象,通信和数据交换、同步操作
- 由于线程间的通信是在同一地址空间上进行的,所以不需要额外的通信机制,这就使得通信更加简便而且信息传递的速度更快。
线程与进程
- 一个进程至少有一个线程。
Javac与java:
javac:编译,启动了Java的编译器,javac就是一个进程,编译结束后,进程结束、消失。
java:执行,启动了Java虚拟机Java运行进程。
线程与进程的区别
Java实现多线程的方式
- 在Java中负责线程功能的类是Java.lang.Thread。
- 可以通过创建Thread的实例来创建新的线程。
- 每一个线程都是通过某个特定的Thread对象的run方法来完成操作的,方法run()被称为线程体。
- 通过调用Thread类的start()方法来启动一个线程。
方法一:
1)继承Thread类
2)重写run方法
3)创建对象,调用start方法启动线程。
缺点:类的父类只能有一个,有时候无法继承Thread类。
方法二:
1)实现Runnable接口
2)重写run方法
3)创建对象,调用start方法,启动线程。
优点:可以同时实现继承。实现Runnable接口方式要通用一些。避免了单继承,方便共享资源、同一份资源、多个代理访问。
线程执行的过程:
线程的生命周期:
**新生:**用new关键字建立一个线程后,该线程对象就处于新生状态。处于新生状态的线程调用start方法进入就绪状态。
**就绪:**处于就绪状态线程具备了运行的条件,系统并未分配cpu所以处于就绪队列。
当系统进行“系统调度”选定一个就绪状态的线程后,它便会进入执行状态。
**运行:**在运行状态的线程执行run方法,直到因为等待资源而进入阻塞状态或者完成任务进入死亡状态。
如果在给定的时间片内没有执行结束,就会被系统给换下来回到就绪状态,继续等待下一次的系统调度。
**阻塞:**处于运行状态的线程执行了sleep方法,让出cpu资源,进入阻塞状态。
当引起阻塞状态的原因消除时,线程重新进入就绪状态。
**死亡:**死亡状态时线程生命周期的最后一个阶段,线程死亡的原因有三个:一个时正常运行的线程完成了全部工作;二是线程被强制性的终止,用stop方法;线程抛出未捕获的异常。
线程操作的相关方法
阻塞状态:
sleep,yield,join可以暂停Thread执行。
sleep:不会释放锁,sleep时别的线程也不可以访问锁定的对象。
yield:让出CPU的使用权,从运行状态直接进入就绪状态。让CPU重新挑选一个线程进入运行状态。
join:当某一个线程等待另一个线程执行完成后,才继续执行。调用该方法的线程在此之前执行完成,也就是等待调用该方法的线程执行完成后再继续执行其他线程。
死锁
使用同步解决线程的安全问题
前提:
- 1)必须有两个以及两个以上的线程。
- 2)必须是多个线程使用同一资源。
- 3)必须保证同步中只能有一个线程在运行。
同步监视器:
- synchronized(obj){}中的obj称之为同步监视器。
- 同步代码块中的同步监视器可以是任何对象,但是推荐使用共享资源作为同步监视器
- 同步方法中无需指定同步监视器,因为同步方法的监视器是this,也就是该对象本身。
线程通信
Java提供了3个方法解决线程之间的通信问题。