Java多线程- synchronized关键字总结

简介: Java多线程- synchronized关键字总结

线程锁的概要

     首先对于锁的条件和要点进行一个总结:

  • 锁使用来保护代码片段的, 以保证多线程的安全性, 一次只允许一个线程执行被保护的代码.
  • 锁可以管理视图进入被保护代码的线程, 提高多线程安全
  • 一个锁可以有一个或多个关联的条件对象

对于synchronized来说, 如果它修饰的是方法, 那么他保护的代码段将是整个方法

Synchronized关键字

       结合锁策略, 可以得出以下结论:

  1. synchronized开始是乐观锁, 如果冲突太频繁了, 那么synchronized就升级为悲观锁
  2. synchronized开始是轻量级锁, 如果单个线程占用synchronized锁的时间长了, 就会变成重量级锁.
  3. 此处的轻量级锁和自旋锁有重叠的部分
  4. synchronized是一种不公平的锁
  5. synchronized是一种可重入锁
  6. synchronized不是读写锁

synchronized加锁过程

  1. 首先对一个无锁的代码段进行加锁,  这个锁会进入偏向锁的状态, 此处的偏向锁不是真正的加锁, 而是给这个锁做一个标记, 表示这个锁属于哪个线程, 如果后续没有线程来抢锁, 那么就不会进行其他同步操作.  如果有的话, 那么这个锁就会升级为真正的锁, 进入一种以自旋锁为基础的轻量级锁状态
  2. 进入轻量级锁, 此处的轻量级锁是通过CAS实现的, 轻量级锁适用于抢锁比较少的多线程环境, 基于自旋锁, 如果其他线程来抢锁就会阻塞等待, 并且在极短时间内进行第二次访问, 直到拿到锁. 但是如果锁长时间没有释放就会造成CPU空转, 浪费CPU资源. 所以如果有多个线程频繁的抢锁, 锁就会升级为重量级锁. 让线程放弃CPU, 进入内核态,此时有操作系统来通知线程这个锁是否被释放, 然后再来调度这些抢锁的线程.
  3. 轻量级锁的竞争激烈后, 就会升级为重量级锁,如果该锁被占用, 则加锁失败. 此时线程进入锁的等待队列, 挂起. 等待被操作系统唤醒.经过一段时间后, 这个锁被其他线程释放了, 操作系统也想起了这个挂起的线程, 于是唤醒这个线程, 尝试重新获取锁.

synchronized锁优化

       锁消除

       遵循于非必要不加锁的规则, synchronized实现了锁消除机制, 也就是在非多线程情况下, synchronized会自动识别线程情况, 自动消除掉不必要的锁,

       例如我们常用的线程安全的StringBuffer, 但是如果在单线程使用, 那么就会在编译的时候去除synchronized关键字, 来减少非必要的开销.

StringBuffer sb = new StringBuffer();
sb.append("a");
sb.append("b");
sb.append("c");
sb.append("d");

此处每次的append操作都会加锁, 造成了非必要的资源浪费

       锁粗化

       在一段代码中, 可能存在两个被保护的代码段, 如下:

如果这两个代码段(代码段1和代码段2)之间, 不存在锁竞争的情况话, 就可以省去中间的解锁和加锁, 这样就避免的多余的加锁解锁操作, 节约了CPU资源


目录
相关文章
|
5天前
|
安全 Java 开发者
深入解读JAVA多线程:wait()、notify()、notifyAll()的奥秘
在Java多线程编程中,`wait()`、`notify()`和`notifyAll()`方法是实现线程间通信和同步的关键机制。这些方法定义在`java.lang.Object`类中,每个Java对象都可以作为线程间通信的媒介。本文将详细解析这三个方法的使用方法和最佳实践,帮助开发者更高效地进行多线程编程。 示例代码展示了如何在同步方法中使用这些方法,确保线程安全和高效的通信。
25 9
|
4天前
|
监控 安全 Java
Java中的多线程编程:从入门到实践####
本文将深入浅出地探讨Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的摘要形式,本文将以一个简短的代码示例作为开篇,直接展示多线程的魅力,随后再详细解析其背后的原理与实现方式,旨在帮助读者快速理解并掌握Java多线程编程的基本技能。 ```java // 简单的多线程示例:创建两个线程,分别打印不同的消息 public class SimpleMultithreading { public static void main(String[] args) { Thread thread1 = new Thread(() -> System.out.prin
|
6天前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
|
1月前
|
存储 消息中间件 资源调度
C++ 多线程之初识多线程
这篇文章介绍了C++多线程的基本概念,包括进程和线程的定义、并发的实现方式,以及如何在C++中创建和管理线程,包括使用`std::thread`库、线程的join和detach方法,并通过示例代码展示了如何创建和使用多线程。
43 1
C++ 多线程之初识多线程
|
23天前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
16 3
|
23天前
|
Java 开发者
在Java多线程编程中,选择合适的线程创建方法至关重要
【10月更文挑战第20天】在Java多线程编程中,选择合适的线程创建方法至关重要。本文通过案例分析,探讨了继承Thread类和实现Runnable接口两种方法的优缺点及适用场景,帮助开发者做出明智的选择。
16 2
|
23天前
|
Java
Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口
【10月更文挑战第20天】《JAVA多线程深度解析:线程的创建之路》介绍了Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口。文章详细讲解了每种方式的实现方法、优缺点及适用场景,帮助读者更好地理解和掌握多线程编程技术,为复杂任务的高效处理奠定基础。
28 2
|
23天前
|
Java 开发者
Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点
【10月更文挑战第20天】Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点,重点解析为何实现Runnable接口更具灵活性、资源共享及易于管理的优势。
28 1
|
23天前
|
安全 Java 开发者
Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用
本文深入解析了Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用。通过示例代码展示了如何正确使用这些方法,并分享了最佳实践,帮助开发者避免常见陷阱,提高多线程程序的稳定性和效率。
33 1
|
23天前
|
Java
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。它们通过基于锁的方式,使线程在条件不满足时进入休眠状态,并在条件成立时被唤醒,从而有效解决数据一致性和同步问题。本文通过对比其他通信机制,展示了 `wait()` 和 `notify()` 的优势,并通过生产者-消费者模型的示例代码,详细说明了其使用方法和重要性。
24 1