一、线程的状态

图片说明
如图上图所示,线程存在六种状态

NEW(新建)
创建后尚未启动

RUNNABLE(就绪)
可以被运行,具体有没有运行要看底层操作系统的资源调度

BLOCKED(阻塞)
请求获取 monitor lock 从而进入 synchronized 函数或者代码块,但是其它线程已经占用了该 monitor lock,所以出于阻塞状态。要结束该状态进入从而 RUNABLE 需要其他线程释放 monitor lock。

WAITING(无限期等待)
不见不散
等待其他线程显式唤醒
阻塞和等待的区别在于,阻塞是被动的,它是在等待获取 monitor lock。而等待是主动的,通过调用 Object.wait() 等方法进入。

进入方法 退出方法
没有设置 Timeout 参数的 Object.wait() 方法 Object.notify() / Object.notifyAll()
没有设置 Timeout 参数的 Thread.join() 方法 被调用的线程执行完毕
LockSupport.park() 方法 LockSupport.unpark(Thread)

TIMED_WAITING(限期等待)
过时不候
无需等待其它线程显式地唤醒,在一定时间之后会被系统自动唤醒。

进入方法 退出方法
Thread.sleep() 方法 时间结束
设置了 Timeout 参数的 Object.wait() 方法 时间结束 / Object.notify() / Object.notifyAll()
设置了 Timeout 参数的 Thread.join() 方法 时间结束 / 被调用的线程执行完毕
LockSupport.parkNanos() 方法 LockSupport.unpark(Thread)
LockSupport.parkUntil() 方法 LockSupport.unpark(Thread)

TERMINATED(死亡)
可以是线程结束任务之后自己结束,或者产生了异常而结束。

二、互斥同步

1.Synchronized

1.同步一个代码块

public void func() {
    synchronized (this) {
        // ...
    }
}

锁的this只作用在同一个对象上,如果调用两个及以上对象的同步代码块就不会同步。

2.同步一个方法

public synchronized void func () {
    // ...
}

它和同步代码块一样,作用于同一个对象。

3.同步一个类

public void func() {
    synchronized (SynchronizedExample.class) {
        // ...
    }
}

作用于整个类,也就是说两个线程调用同一个类的不同对象上的这种同步语句,也会进行同步。

public class SynchronizedExample {
    public void func2() {
        synchronized (SynchronizedExample.class) {
            for (int i = 0; i <= 10; i++) {
                System.out.print(i);
            }
        }
    }
}
public static void main(String[] args) {
    SynchronizedExample e1 = new SynchronizedExample();
    SynchronizedExample e2 = new SynchronizedExample();
    ExecutorService executorService = Executors.newCachedThreadPool();
    executorService.execute(() -> e1.func2());
    executorService.execute(() -> e2.func2());
}
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9

4.同步一个静态方法

public synchronized static void fun() {
    // ...
}

作用于整个类,和同步一个类是一样的

2.ReentrantLock

这里要涉及到AQS

三、并发编程中的三个概念

可见性、原子性、有序性

1.有序性演示

jcstress是java并发压测工具。
修改pom文件,添加依赖:

    <dependencies>
        <dependency>
            <groupId>org.openjdk.jcstress</groupId>
            <artifactId>jcstress-core</artifactId>
            <version>0.5</version>
        </dependency>
        <dependency>
            <groupId>org.openjdk.jcstress</groupId>
            <artifactId>jcstress-samples</artifactId>
            <version>0.5</version>
        </dependency>
    </dependencies>
@JCStressTest
@Outcome(id = {"1", "4"}, expect = Expect.ACCEPTABLE, desc = "ok")
@Outcome(id = "0", expect = Expect.ACCEPTABLE_INTERESTING, desc = "danger")
@State
public class T03Ordering {
    int num = 0;
    boolean ready = false;

    @Actor
    public void actor1(I_Result r) {
        if (ready) {
            r.r1 = num + num;
        } else {
            r.r1 = 1;
        }
    }

    @Actor
    public void actor2(I_Result r) {
        num = 2;
        ready = true;
    }

}
//压测结果显示
Observed state   Occurrences              Expectation  Interpretation                                              
               0           560   ACCEPTABLE_INTERESTING  danger                                                      
               1    74,567,949               ACCEPTABLE  ok                                                          
               4    24,642,982               ACCEPTABLE  ok         

程序代码在执行过程中的先后顺序,由于Java在编译期以及运行期的优化,导致了代码的执行顺序未必就是开发者编写代码时的顺序。

可重入锁
遇到异常 释放锁

synchronized实现
重量级
锁升级的概念
无锁
对象头记录线程id 偏向锁
线程征用 自旋锁
10次以后
升级为重量级锁

线程的概念、启动方式、常用方法