Java并发编程(二)线程的基本认知

线程的各个术语

线程和进程的区别

进程可以比喻为一个app,淘宝,美团,微信都是一个进程,线程是属于进程的。就好似微信里面的群发就是多个线程在工作。也可以比喻为,进程是一户人家,家里有多个人(线程),每个人都有各自的职业,在大多数时候一起分工合作(提高效率),少数时候发生冲突,比如一起抢一个厕所(线程阻塞)。

线程的生命周期

在线程这个类中,有一个枚举类,枚举了线程的各个状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public enum State {

NEW,

RUNNABLE,

BLOCKED,

WAITING,

TIMED_WAITING,

TERMINATED;
}

NEW表示尚未启动的线程的线程状态

RUNNABLE表示它是一个正在运行的线程

BLOCKED表示线程被阻塞,无法获得想要获得的资源,可能是资源正在被锁定,或等待被解锁

WAITING由于调用其中一个线程,线程处于等待状态

TIMED_WAITING具有指定等待时间的等待线程的线程状态

TERMINATED终止线程的线程状态

我们可以通过接取一个Runnable接口来使用并行的功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class test implements Runnable{
public static void main(String[] args) throws InterruptedException {
test r = new test();
Thread t = new Thread(r);
System.out.println(t.getState());
t.start();
System.out.println(t.getState());
t.sleep(1000);
System.out.println(t.getState());

}
@Override
public void run() {
System.out.println("xxxx");
}
}

//NEW
//RUNNABLE
//xxxx
//TERMINATED

使用thread.getstate()获得此线程此刻的状态

线程的切换

CPU通过时间片分配算法来循环执行任务,当前任务执行一个时间片后会切换到下一个任务。

在切换前会保存上一个任务的状态,以便下次切换回这个任务时,可以再加载这个任务的状态。

所以任务从保存到再加载的过程就是一次线程切换

并发的级别

1 阻塞

一个线程是阻塞的,那么在其他线程释放资源之前,当前线程无法继续执行。阻塞可以分很多情况,一种是临时阻塞,就是当时要访问的资源暂时被锁住的了无法访问,所以就停留在此地,另一种是碰到了死锁,就会一直被阻塞,直到设计者发现它。

2 无饥饿(Starvation-Free)

如果线程之间是有优先级的,那么线程调度的时候总是会倾向于满足高优先级的线程。也就是说,对于同一个资源的分配,是不公平的。锁也分公平锁和非公平锁,对于非公平锁来说,系统允许高优先级的线程插队。这样就有可能导致低优先级的线程产生饥饿。但是如果是公平锁,满足先来后到,那么饥饿就不会产生,不管新来的线程优先级多高,要想获得资源,就必须乖乖排队。这样所有的线程都有机会执行。

3 无障碍(Obstruction-Free)

无障碍是一种最弱的非阻塞调度。无障碍表示两个线程可以畅通无阻的行动,但也会出现一些矛盾,比如一起访问同一个资源,又一起修改一个资源,那样就会出现数据的不可见性,对于无障碍的线程来说,一旦检测到这种情况,它就会立即对自己所做的修改进行回滚,确保数据安全。

4 无锁(Lock-Free)

无锁的并行都是无障碍的。但是这样会出现很多很多问题,比如说也是同时访问和修改资源,如果发生了资源的争夺,可能会陷入长时间的阻塞或者是直接奔溃,这对于程序来说,无疑是致命的。

5 无等待(Wait-Free)

无锁只要求一个线程可以在有限步数内完成操作,而无等待则是在无锁的基础上更进一步进行扩展,它要求所有的线程都必须在有限步数内完成,这样就不会引起线程饥饿问题。