Java Concurrency
Java Concurrency
获取线程的执行结果
创建线程有 3 种方式,一种是直接继承 Thread,一种是实现 Runnable 接口,另外一种是实现 Callable 接口。前 2 种方式都有一个缺陷:在执行完任务之后无法获取执行结果。
如果需要获取执行结果,就必须通过共享变量或者线程通信的方式来达到目的,这样使用起来就比较麻烦。
Java 1.5 提供了 Callable、Future、FutureTask,它们可以在任务执行完后得到执行结果。
Callable接口
Callable接口定义了一个 call()
方法,返回的类型是一个 V 类型的范型。在之前的例子中,我们使用String来作为范型的具体类型。
线程的声明周期与状态
多线程带来的问题
线程死锁
两个或两个以上的进程(线程)在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象。
形成死锁的四个必要条件
1. 互斥条件
线程(进程)对于所分配到的资源具有排它性,即一个资源只能被一个线程(进程)占用,直到被该线程(进程)释放
2. 请求与保持条件
一个线程(进程)因请求被占用资源而发生阻塞时,对已获得的资源保持不放。
3. 不剥夺条件
线程(进程)已获得的资源在末使用完之前不能被其他线程强行剥夺,只有自己使用完毕后才释放资源。
4. 循环等待条件
当发生死锁时,所等待的线程(进程)必定会形成一个环路(类似于死循环),造成永久阻塞
避免线程死锁——破坏其一条件
我们只要破坏产生死锁的四个条件中的其中一个就可以了。
- 破坏互斥条件
这个条件我们没有办法破坏,因为我们用锁本来就是想让他们互斥的(临界资源需要互斥访问)。
- 破坏请求与保持条件
一次性申请所有的资源。
- 破坏不剥夺条件
占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源。
- 破坏循环等待条件
靠按序申请资源来预防。按某一顺序申请资源,释放资源则反序释放。破坏循环等待条件。
线程安全:确保多线程数据一致性
为了确保多线程环境下数据的一致性,可以采取以下几种方法:
1. 使用同步机制
通过使用锁、互斥量、信号量等同步机制,可以保证在同一时间只有一个线程能够访问和修改共享数据,从而避免数据竞争和冲突。
2. 使用原子操作
原子操作是指不可中断的操作,可以保证在执行期间不会被其他线程中断。通过使用原子操作,可以避免多线程环境下的数据竞争和冲突。
3. 使用线程安全的数据结构
线程安全的数据结构是指在多线程环境下能够保证数据操作的正确性和一致性的数据结构。例如,使用线程安全的队列、哈希表等数据结构可以避免数据竞争和冲突。
4. 使用同步工具
同步工具是指用于协调和同步多个线程之间操作的工具。例如,使用信号量、条件变量等同步工具可以确保多线程环境下数据的一致性。