单机高并发应该掌握的线程基础:线程状态,异常与锁等

什么是线程

进程:操作系统资源分配的基本单位
线程:进程的最小执行单元

线程实现

启动线程的三种方式: 继承Thread、实现 Runnable、通过线程池 Executors.newCachedThread

public class HowToCreateThread {

    private static class T1 extends Thread {
        @Override
        public void run() {
            System.out.println("T1 = " + Thread.currentThread().getName());
        }
    }

    private static class T2 implements Runnable {
        @Override
        public void run() {
            System.out.println("T2 = " + Thread.currentThread().getName());
        }
    }

    public static void main(String[] args) {
        T1 t1 = new T1();
        t1.start();

        Thread t2 = new Thread(new T2());
        t2.start();

        Thread t3 = new Thread(() -> {
            System.out.println("T3 = " + Thread.currentThread().getName());
        });
        t3.start();

        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.execute(() -> {
            System.out.println("T4 = " + Thread.currentThread().getName());
        });
        executorService.shutdown();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

常用方法

常用方法:sleep yield join

  • sleep
    • 当前线程暂停,让给别的线程
    • 等待指定时间后自动复活
    • sleep完,也是回到就绪状态
  • yield
    • 回到等待队列(让出一下CPU)
    • 返回就绪状态(Running->Ready)
  • join
    • 加入其它线程
    • t1线程调用t2.join() t1->t2.join->t1->end
    • 常用来等待其它线程结束

线程状态

  • New 创建线程,还没调用start()方法
  • Runnable 调用start()方法后(被线程调度器执行)
    • Ready 就绪状态(在CPU等待队列)
    • Running 运行状态(真正的在CPU上运行)
  • Timed_Waiting
  • Waiting
  • Blocked 加上同步代码块synchronized,没得到锁
  • Terminated 执行结束进入该状态,不能再调用start()

线程同步

synchronized关键字

  • 锁的是对象不是代码
  • 对象方法 <=> synchronized(this)
  • 静态方法 <=> synchronized(T.class)
public class FineCoarseLock {
    //等同于在方法的代码执行时要synchronized(this)
    public synchronized void lockThis() {
        System.out.println("FineCoarseLock = " + Thread.currentThread().getName());
    }

    //这里等同于synchronized(FineCoarseLock.class)
    public synchronized static void lockStatic() {
        System.out.println("FineCoarseLock = " + Thread.currentThread().getName());
    }
}
1
2
3
4
5
6
7
8
9
10
11
  • synchronized同时保证了原子性和可见性
  • 不能用String常量、Integer、Long(池化)

同步方法与非同步方法

  • 锁定方法(同步) 非锁定方法(非同步) 可以同时执行

可重入

  • 一个同步方法可以调用另外一个同步方法,一个线程已经拥有某个对象的锁,再次申请的时候仍然会得到该对象的锁.
  • 也就是说synchronized获得的锁是可重入的
  • 这里是继承中有可能发生的情形,子类调用父类的同步方法

异常与锁

  • 程序在执行过程中,如果出现异常,默认情况锁会被释放

锁升级

  • 无锁—>偏向锁->自旋锁->重量级锁
  • 没有降级?

synchronized的底层实现

  • JDK早期的 重量级 - OS

  • 锁升级 sync(Object)

    • markword 记录这个线程ID (偏向锁)
    • 如果线程争用:升级为 (自旋锁)
    • 10次以后,升级为 (重量级锁) - OS
  • 锁的使用

    • 执行时间短(加锁代码),线程数少,用自旋
    • 执行时间长,线程数多,重量级锁
  • 自旋锁 用户态 占用CPU时间 不访问操作系统

  • 系统锁 访问操作系统(经过OS),进入等待队列,不占CPU

总字数: 907 字  上次更新: 2023-03-14 00:25:11