Java并发编程

进程与线程的概念

(1)什么是进程

进程:程序由指令和数据组成,

(2)什么是线程

  • 一个进程可以有多个线程
  • 一个线程就是一个指令流,将指令流中的一条条指令以一定的顺序交给CPU执行
  • 线程作为任务调度的最小单位,进程作为资源分配的最小单位

并发与并行的概念

(1)什么是并发(Concurrent)

同一时刻多个线程轮流使用CPU,并不是同时执行的。

(1)什么是并行

同一时刻多个线程同时使用CPU,一般是多核CPU,因此是同时执行的。

创建线程的方法

继承Thread类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Concurrent {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.setName("子线程:");
//开启线程
myThread.start();
}

}

class MyThread extends Thread{
//重写run()方法
public void run(){
for(int i = 0;i < 5; i++){
System.out.println(Thread.currentThread().getName() + i);
}
}
}

实现Runnable接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Concurrent {
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable());
thread.setName("子线程:");
//开启线程
thread.start();
}

}

class MyRunnable implements Runnable {

@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + i);
}
}
}

实现Callable接口

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
public class Concurrent {
public static void main(String[] args) {
//执行Callable 方式,需要FutureTask 实现实现,用于接收运算结果
FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyCallable());
new Thread(futureTask).start();
//接收线程运算后的结果
try {
Integer sum = futureTask.get();
System.out.println(sum);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}

}

class MyCallable implements Callable<Integer> {

@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 0; i < 5; i++) {
sum += i;
}
return sum;
}
}

使用线程池

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Concurrent {
public static void main(String[] args) {
//创建线程池
ExecutorService executorService = Executors.newFixedThreadPool(5);//创建固定线程数量的线程池
ThreadPool threadPool = new ThreadPool();
//为线程池分配任务
executorService.submit(threadPool);
//关闭线程池
executorService.shutdown();
}
}

class ThreadPool implements Runnable {

@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}

主线程和守护线程

默认情况下,Java进程需要等待所有线程都运行结束才会结束

守护线程:只要其他非守护线程都运行结束了,即使守护线程的代码没有执行完,也会强制结束。
启动之前:thread.setDaemon(true);即可设置该线程为守护线程。

垃圾回收线程就是一种守护线程。

线程的几种状态

从操作系统层面(五种)

img

新建/初始状态

新创建了一个线程对象。

就绪/可运行状态

指该线程已经被创建,等待 CPU 调度执行。

运行状态

指获取了 CPU 时间片运行中的状态

当 CPU 时间片用完,会从【运行状态】转换至【可运行状态】,会导致线程的上下文切换

阻塞状态

等 BIO 操作完毕,会由操作系统唤醒阻塞的线程,转换至【可运行状态】
与【可运行状态】的区别是,对于【阻塞状态】的线程来说只要它们一直不唤醒,调度器就一直不会考虑调度它们

死亡状态

表示线程已经执行完毕,生命周期已经结束,不会再转换为其它状态

参考:

线程的5种状态详解

从JAVA层面(六种)

img

初始状态

新创建了一个线程对象,但还没有调用start()方法。

运行状态

Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。

线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行中状态(running)。

阻塞状态

表示线程阻塞于锁。

等待状态

进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。

超时等待状态

该状态不同于等待(WAITING),它可以在指定的时间后自行返回。

终止状态

表示该线程已经执行完毕。

参考:

Java线程的6种状态及切换

线程的状态在操作系统层面和JAVA API层面的区别

Sleep和Wait的区别

Run和Start的区别