c++实现java synchronized关键字

本文介绍了一个使用互斥锁实现安全并发访问数据结构的模板类。通过重载运算符实现对象加锁与解锁,确保了多线程环境下数据的一致性和安全性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

// 重载对象的"+= / -="实现访问加锁,重载 "=" 实现访问解锁。从而实现互斥访问对象。


// 互斥模块类


#pragma once
#include "stdafx.h"


// 用于实现互斥的模版类
// 作者:陈 A Z
// 时间:2016/12/18


template <typename T>
class CSyncParam
{
public:
// 互斥锁
    HANDLE m_hMutex;


public:
// 数据成员
T td;


CSyncParam();
~CSyncParam();


void MakeData(T t);


// 开启对象锁
void SetLock();


// 释放对象锁
void ReleaseLock();


// 用来解锁互斥
CSyncParam<T> operator=(CSyncParam<T> & csp);


// 互斥读写成员
CSyncParam<T> operator+=(CSyncParam<T> & csp);
// 互斥读写成员
CSyncParam<T> operator-=(CSyncParam<T> & csp);
};


// 开启互斥等待
template <typename T>
void CSyncParam<T>::SetLock()
{
// 加锁
//printf("加锁地址 : %d \n", &m_hMutex);
// 开始访问要锁住
WaitForSingleObject(m_hMutex, INFINITE);
}


// 释放互斥对象
template <typename T>
void CSyncParam<T>::ReleaseLock()
{
// 解锁
//printf("释放地址 : %d \n", &m_hMutex);
ReleaseMutex(m_hMutex);
}


// 解锁访问对象
template <typename T>
CSyncParam<T> CSyncParam<T>::operator=(CSyncParam<T> & csp)
{
// 直接拷贝
memcpy(this, &csp, sizeof(CSyncParam<T>));


// 释放间接对象
csp.ReleaseLock();
// 释放间接对象
this->ReleaseLock();


return *this;
}


// 加锁读写
template <typename T>
CSyncParam<T> CSyncParam<T>::operator+=(CSyncParam<T> & csp)
{
// 加锁方可访问
csp.SetLock();
this->SetLock();


// 加锁方可访问
// 直接拷贝
memcpy(this, &csp, sizeof(CSyncParam<T>));


return *this;
}


// 加锁读写
template <typename T>
CSyncParam<T> CSyncParam<T>::operator-=(CSyncParam<T> & csp)
{
// 加锁方可访问
csp.SetLock();
this->SetLock();


// 加锁方可访问
// 直接拷贝
memcpy(this, &csp, sizeof(CSyncParam<T>));


return *this;
}


// 互斥的数据
template <typename T>
void CSyncParam<T>::MakeData(T t)
{
td = t;
}


template <typename T>
CSyncParam<T>::~CSyncParam()
{
//CloseHandle(m_hMutex);
FindClose(m_hMutex);
}


template <typename T>
CSyncParam<T>::CSyncParam()
{
m_hMutex = CreateMutex(NULL, FALSE, NULL);
}


//template <typename T>
//HANDLE CSyncParam<T>::m_hMutex;


// 主文件
// Sync.cpp : 定义控制台应用程序的入口点。
// 


#include "stdafx.h"


#include "SyncParam.h"
#include "process.h"


#include <vector>
using namespace std;


// 线程处理过程
void ThreadProc(void * pParam);


#define SYNC_PARAM_START(value_type) CSyncParam<##value_type>


#define SYNC_L CSyncParam<
#define SYNC_R  >


// 声明对象
SYNC_PARAM_START(vector<int>) cp;


//CSyncParam<vector<int>> cp;
//CSyncParam<vector<int>> * cy = new CSyncParam<vector<int>>;


int _tmain(int argc, _TCHAR* argv[])
{
// 构造数据
vector<int> vec;
for (int i = 0; i < 100; i++)
{
vec.push_back(i);
}
// 填充数据
cp.MakeData(vec);


// 开多个线程同时卖票
for (int i = 10; i >= 0; i--)
{
_beginthread(ThreadProc, NULL, NULL);
}


while (1)
{


}


Sleep(10000);
printf("准备退出!");
return 0;
}


//SYNC_PARAM_START (vector<int>) cy;


// 宏拼接对象
SYNC_L vector<int> SYNC_R cy;


void ThreadProc(void * pParam)
{
while (1)
{
// 互斥访问开始
cy -= cp;


vector<int> & vd = cy.td;


if (vd.size())
{
vd.pop_back();
}
if (vd.empty())
{
return;
}
printf(“卖票编号:%2d 线程ID:%d \n", vd.size(), GetCurrentThreadId());


// 解锁互斥结束
cp = cy;
Sleep(10);


//cy->ReleaseLock();
//cy->ReleaseLock();
}
}







<think>我们正在讨论Java中的synchronized关键字。根据引用内容,synchronized关键字用于实现线程同步,防止多个线程同时执行同步代码块,从而避免竞态条件和数据不一致问题。它的底层实现涉及到对象头中的Mark Word、锁升级过程(偏向锁、轻量级锁、重量级锁)等。 用户问题:理解Javasynchronized关键字实现原理及其在多线程编程中的应用场景 回答结构: 1. synchronized关键字的作用 2. synchronized的底层实现原理(包括对象头、锁升级过程) 3. synchronized在多线程中的应用场景(示例) 4. 注意事项 根据引用[1][2][3][4][5],我们可以整理如下: 1. 作用:确保多个线程在访问共享资源时的协调和同步,避免竞态条件。 2. 实现原理: - 每个Java对象都有一个对象头,其中包含Mark Word(存储锁信息)。 - Mark Word在不同锁状态下存储的内容不同(无锁、偏向锁、轻量级锁、重量级锁)。 - 锁升级过程(优化): 无锁 -> 偏向锁(当只有一个线程访问时) -> 轻量级锁(当有多个线程交替访问,但未同时竞争) -> 重量级锁(当有多个线程同时竞争) 3. 应用场景:多线程环境下对共享资源的访问控制,例如: - 单例模式的双重检查锁定 - 线程安全的计数器 - 共享数据结构的操作(如Vector、Hashtable等) 4. 注意事项:synchronized是重量级锁(在升级到重量级锁时)会涉及到操作系统状态的切换,影响性能。但在JDK1.6后进行了优化,引入了偏向锁和轻量级锁,减少了性能开销。 下面详细展开:</think>### Java synchronized 关键字实现原理及应用场景 #### 一、synchronized 的作用 `synchronized` 是 Java 中的**同步锁关键字**,用于解决多线程环境下的**线程安全问题**: 1. **防止竞态条件**:确保同一时刻只有一个线程访问共享资源。 2. **保证可见性**:线程对共享变量的修改对其他线程立即可见。 3. **实现有序性**:禁止指令重排序优化。 > 典型应用场景:多线程卖票系统、单例模式、共享计数器、线程安全的集合类(如 `Vector`)[^2]。 --- #### 二、底层实现原理 ##### 1. 对象头与 Mark Word 每个 Java 对象在内存中包含**对象头**(Object Header),其中关键部分是 **Mark Word**(占 64 位 JVM 中的 64 位): | 锁状态 | Mark Word 存储内容 | 标志位 | |--------------|-------------------------------------|--------| | **无锁** | 哈希码 + 分代年龄 | `01` | | **偏向锁** | 线程 ID + 时间戳 + 分代年龄 | `101` | | **轻量级锁** | 指向栈中锁记录的指针 | `00` | | **重量级锁** | 指向互斥量(monitor)的指针 | `10` | ##### 2. 锁升级流程 JDK 1.6 后引入**锁升级优化**(避免直接使用重量级锁): ```mermaid graph LR A[无锁] -->|首次获取锁| B[偏向锁] B -->|发生竞争| C[轻量级锁] C -->|自旋失败| D[重量级锁] ``` - **偏向锁**:仅一个线程访问时,通过 CAS 将线程 ID 写入 Mark Word。 - **轻量级锁**:多个线程交替执行,通过 CAS 和自旋尝试获取锁。 - **重量级锁**:竞争激烈时,线程进入阻塞状态,由操作系统管理互斥量(monitor)[^3][^4]。 ##### 3. Monitor 机制 - 当升级到重量级锁时,Mark Word 指向 **ObjectMonitor** 对象(C++ 实现)。 - ObjectMonitor 包含: - `_owner`:持有锁的线程 - `_EntryList`:阻塞等待锁的线程队列 - `_WaitSet`:调用 `wait()` 的线程队列 > 同步代码块编译后生成 `monitorenter` 和 `monitorexit` 指令,由 JVM 调用 ObjectMonitor 的锁机制[^5]。 --- #### 三、应用场景示例 ##### 1. 同步代码块(显式锁对象) ```java public class Counter { private int count = 0; private final Object lock = new Object(); // 专用锁对象 public void increment() { synchronized(lock) { // 锁定特定对象 count++; } } } ``` ##### 2. 同步方法(锁当前实例) ```java public synchronized void safeWrite() { // 锁定当前实例(this) } ``` ##### 3. 静态同步方法(锁 Class 对象) ```java public static synchronized void staticSafeMethod() { // 锁定类的 Class 对象(如 Counter.class) } ``` --- #### 四、性能优化建议 1. **减小同步范围**:尽量使用同步代码块而非同步方法。 2. **避免锁嵌套**:防止死锁和性能下降。 3. **考虑替代方案**:高并发场景用 `ReentrantLock` 或 `StampedLock`。 4. **锁分离技术**:如 `ReadWriteLock` 分离读/写锁。 > 统计表明:80% 的锁在无竞争时通过偏向锁/轻量级锁可降低开销至纳秒级[^3]。 --- #### 五、常见问题解析 1. **Q: 为什么 `String` 不适合作为锁对象?** A: 字符串常量池可能被多个类共享,导致意外锁竞争。 2. **Q: `synchronized` 和 `volatile` 的区别?** A: `volatile` 仅保证可见性和有序性,不保证原子性;`synchronized` 三者均保证。 3. **Q: 锁升级是否可逆?** A: 偏向锁可撤销回无锁状态;重量级锁无法降级。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值