Java线程知识点整合
基础
线程相关概念
程序(program):是为完成特定任务,用某种语言编写的一组指令的集合(也就是我们写的代码)。
线程是由进程/另一个线程创建的,是进程的一个实体。
一个进程可以拥有多个线程。
单线程
多线程
并发
并行
线程使用
- 创建线程的方式:
- 继承Thread接口
- 实现Runnable接口
- 使用Callable (用得很少)
继承Thread接口
1 | class Cat extends Thread { |
多线程的情况下,一个进程的所有线程都结束了的时候,这个进程才会挂掉。
Java中真正实现多线程的是start()中的start0(),而不是run()。开启线程的操作是start(),调用run()就只是简单地调用这个方法而已,相当于是串行化地执行,并没有开启一个线程。
(源码底层)在start()方法中会调用一个start0()方法,就是它这个方法真正实现了多线程。start0()是一个native方法,由JVM直接调用,底层由C/C++实现。start()调用完start0()后,该线程并不一定会立即执行,只是将线程变成了可运行状态。具体什么时候执行取决于CPU,由CPU统一调度。
实现Runnable接口
1 | Class Test { |
底层使用了(静态)代理模式。为了方便理解,我们来写一个“极简的”Thread类:
1 | class ThreadProxy implements Runnable { |
[继承Thread]与[实现Runnable]的区别
- 从Java的设计来看,通过继承Thread和实现Runnable接口这两种创建线程的方式在本质上没有区别,我们从JDK帮助文档中可以看到Thread类本身就实现了Runnable接口。底层都是在start()中调用了start0()。
- 如果没有特殊要求,建议采用实现Runnable接口的方式,这种方式适合多个线程共享一个资源的情况,而且避免了单继承的限制。
线程方法
线程生命周期
synchronized
互斥锁
- Java中引入了对象互斥锁的概念来保证共享数据操作的完整性。
- 每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
- 关键字synchronized来与对象的互斥锁联系。当某个对象用synchronized修饰时,表明该对象在任一时刻只能由一个线程访问。
- 同步的局限性:导致程序的执行效率降低。
- 同步方法(非静态的)的锁对象可以是this,也可以是其他对象(要求是同一个对象)。默认是this。
- 同步方法(静态的)的锁对象默认是当前类.class。
死锁
多个线程都占用了对方的锁资源,但不肯相让,导致死锁。
下面的操作不会释放锁:
- 线程执行同步代码块/同步方法时,程序调用Thread.sleep()、Thread.yield()方法暂停当前线程的执行,不会释放锁。
- 线程执行同步代码块时,其他线程调用了该线程的suspend()方法将该线程挂起,该线程不会释放锁。
提示:应尽量避免使用suspend()和resume()来控制线程,方法不再推荐使用(已过时)。
进阶:
并发基础
线程
锁
线程池
并发容器
JUC
executor
collections
locks
atomic(原子类)
tools(CountDownLatch, Exchanger, ThreadLocal, CyclicBarrier)
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 怀民亦未寝。!