线程
exe双击启动一个程序。
线程是一个程序里不同的执行路径。
调用run方法,还是一条路径,要启动多线程,需要调用start方法。
cpu没有线程的概念,只知道取指令运行。而多线程就是说,如果是单核cpu,它就按照时间片交替执行这些线程。
启动线程方式
- extends Thread 重写run方法,直接调用start启动
new Thread().start();
- implement Runnable 重写run方法,在thread对象中,传入Runnable对象,调用start启动
new Thread(new MyRun).start();
- Executors.newCachedThread 线程池启动
- 用lambda表达式
new Thread(() -> {sout("hello");}).start();
1
2
3
4
5
6
7
8
9T t = new T();
new Thread(t::fun(), "name").start();
// 1.8之前是下面的写法
new Thread(new Runnable() {
public void run() {
t.fun();
}
}).start();
yield、sleep、join
- yield本质上是让出一下cpu,返回就绪状态。之后还是会参加cpu争抢。
- sleep就是该线程睡一会,返回阻塞态,规定时间后自动复活。
- join其实是等待其他线程结束再继续运行。比如在t1线程中调t2.join,就是t1先暂停,t2执行完了,再回到t1继续执行。
【比如在顺序执行几个线程的时候,可以使用join】
线程状态
- JVM是跑在操作系统上的一个普通程序。
- 正常结束线程,就相当于线程关闭了。
- 起一个线程,正常来说,就是os中有一个线程和它一一对应。但是虚拟机启动完了之后,本身这个虚拟机里头还会起GC线程之类的,所以操作系统起的线程要大于你原来的线程。
- stop()不建议使用了。
- interrupt()在底层控制流程中有使用。自己写工程代码很少有人用它来控制业务逻辑。平时使用场景:sleep了两天,调用interrupt()来catch异常。sleep、join、wait的时候,都有可能被打断(interrupt)打断后会抛出异常,你需要进行catch。如果catch到一个异常,接下来的操作需要你根据情况来完成。
加锁的方法和不加锁的方法可以同时运行。
模拟银行账户。对业务写加锁,读不加锁,可能会出现什么问题?脏读。比如setName的方法中,sleep几秒,getName会读到还没有commit的数据。但是能不加就不加,效率太低。