JAVA并发编程
1. 介绍
1.1 进程与线程
1.1.1 概念
进程:计算机中的程序关于某数据集合上的一次运行活动,是操作系统进行资源分配与调度的基本单位(比如内存、文件句柄、安全证书)。程序在各自的进程上运行,可以简单理解为运行的程序。
线程:是进程的一个执行单元,以单一顺序的控制流作为进程的执行分支。共享进程范围内的资源(比如内存、文件句柄),但都有自己的程序计数器、栈和本地变量。
1.1.2 线程的优点
- 降低开发和维护的开销
- 在GUI程序中改进用户接口的响应性
- 在服务器应用中提高资源的利用率和吞吐量
1.1.3 线程的风险
- 安全危险:线程交替占有运行时,导致意外结果。
- 活跃度的危险:多线程带来活跃度失败,如死锁、饥饿、活锁。
- 性能危险:上下文切换(挂起当前线程,运行另一个线程)的频繁进行导致巨大的系统开销;同步机制限制编译器的优化。
1.1.4 线程引入的开销
- 上下文切换
- 内存同步
- 阻塞
1.1.5 Java中的线程
JVM启动时会创建一个主线程,该主线程负责执行main方法;以及一些进行自身的常规管理线程(如垃圾回收、终结处理)。
1.2 并行与并发
- 并行(parallel):同时处理多个任务
- 并发(concurrent):有处理多个任务的能力,但不一定是同时。
1.3 Java线程操作
1.3.1 创建与启动
-
创建一个线程就是创建Thread类对象,可以直接定义Thread类子类或定义Runnable接口的实现类,并重写run方法,即线程要执行的任务。
// 方法一 public class MyThread extends Thread{ @override public void run(){ //do something in a thread } } //方法二 public class MyRunnable implements Runnable{ @override public void run(){ //do something in a thread } } -
启动线程即调用Thread类的start()方法。
//方法一 MyThread myThread = new MyThread(); myThread.start(); //方法二 MyRunnable myRunnble = new MyRunnable(); Thread thread = new Thread(myRunnable); thread.start(); //或直接创建Runnable的匿名类对象或lambda表达式 new Thread(() -> { //do something in a thread. }).start;
1.3.2 Thread类常用方法
| 方法名 | 返回值 | 描述 |
|---|---|---|
| currentThread() | static Thread | 返回执行当前代码的线程 |
| getName() | String | 返回线程名称 |
| setName() | void | 设置线程名称 |
| getId() | long | 返回线程的唯一标识 |
| isAlive() | boolean | 判断是否处于活动状态 |
| sleep(long) | static void | 让当前线程休眠数毫秒 |
| yield() | static void | 放弃当前CPU资源 |
| setPriority() | void | 设置优先级1-10,越大越优先 |
| getPriority() | int | 返回线程优先级 |
| interrupt() | void | 设置中断标志为true,并不一定中断线程 |
| isInterrupt() | boolean | 判断线程中断标志 |
| interrupted() | static boolean | 判断当前线程中断标志 |
| setDaemon(boolean) | void | 设置线程为守护线程 |
| isDaemon() | boolean | 判断是否为守护线程 |
| getState() | Thread.state | 返回线程状态 |
| join(),join(long) | void | 在主线程中调用其他线程的join()可使主线程等待,执行调用join的线程 |
1.3.3 线程的生命周期(状态)
线程的生命周期就是线程的状态,由Thread.state枚举类型定义,有以下几种:
| 类型 | 描述 |
|---|---|
| NEW | 创建线程后未启动的状态 |
| RUNNABLE | 线程启动后的状态,包含ready和running,调用yield()会转成ready |
| BLOCKED | 阻塞状态,发起阻塞I/O操作或申请锁后 |
| WAITING | 执行wait(),join()后会使调用线程或所在线程等待 |
| TIME_WAITED | 执行wait(long),join(long)后会使调用线程或所在线程等待有限时间 |
| TERMINATED | 终止状态,run()程序运行结束后 |
2 线程安全
2.1 概念
2.1.1 线程安全定义
当多个线程访问一个类时,如果不用考虑这些线程在运行时环境下的调度和交替执行,并且不需要额外的同步及在调用方代码不必作其他的协调,这个类的行为仍然是正确的,那么称这个类时线程安全的。即线程安全的类封装了必要的同步。
2.1.2 非线程安全
非线程安全主要是指多个线程对同一个对象的实例变量进行操作时,会出现值被更改并且值可能不同步的情况。
2.1.3 线程安全体现
三个方面:原子性、可见性和有序性
2.2 原子性
2.2.1 含义
原子性即不可分割性,体现为访问某个共享变量的操作从其他线程来看,要么已经执行完毕,要么尚未发生。
2.2.2 例子
对变量自增包含“读-改-写”三个操作,在缺乏同步的情况下会出错。
2.2.3 实现方法
- 锁
- CAS(Compare And Swap)
2.3 可见性
2.3.1 含义
在多线程环境中,一个线程对某个共享变量更新之后,后续其他线程可能无法立即读到更新的结果。
- 如果一个线程更新一个变量后,其他线程可以读到更新结果,则是可见的。
2.3.2 实现方法
- 锁
- volatile
本文介绍了JAVA并发编程的基础知识,包括进程与线程的概念、优缺点,Java中的线程操作,以及线程安全的重要性。详细讲解了线程安全的三大特性:原子性、可见性和有序性,强调了在多线程环境下确保数据一致性的重要机制。

1219

被折叠的 条评论
为什么被折叠?



