线程间数据共享

目录

一、并发运行

二、串行运行

三、多线程同步原理

四、synchronized关键字

五、死锁


一、并发运行

1、线程中并发指一个时间段中多个线程都处于已启动但没有运行结束的状态。
2、多个线程之间默认并发运行,这种运行方式往往会出现交叉的情况。

 

二、串行运行

使原本并发运行的多个线程实现串行运行,即多线程间同步执行,需要通过对象锁机制来实现,synchronized就是一个利用锁实现线程同步的关键字。

synchronized对象锁:该对象锁是Java中创建的一个对象,该对象可由任意类创建,只要求所创建的对象在多个线程之间共享即可。如果对象锁为全局成员,为了保证该对象在多个线程间共享,该成员往往被private static final修饰。

通过synchronized关键字实现了线程串行运行:一个线程执行完synchronized 代码块后另一个线程才执行,但是哪个线程先执行synchronized 代码块中的代码无法确定

 

三、多线程同步原理

为什么通过synchronized就能实现多线程间串行运行呢?
1、被synchronized括着的部分就是线程执行临界区,每次仅能有一个线程执行该临界区中的代码:当多个线程中的某个线程先拿到对象锁, 则该线程执行临界区内的代码,其他线程只能在临界区外部等待,当此线程执行完临界区中的代码后,在临界区外部等待的其他线程开始再次竞争以获取对象锁,进而执行临界区中的代码,但只能有一条线程“胜利”。
2、临界区中的代码具有互斥性、唯一性和排它性:一个线程只有执行完临界区中的代码另一个线程才能执行。

为什么这行代码60秒左右才会执行?        

显示器线程和时间线程共享lockObj对象,显示器线程优先进入启动状态,随后执行相应的run方法,当执行同步代码块时lockObj变量所代表的对象锁归显示器线程所有,进而创建时间线程并使之处于启动状态,此时有一下两种状态:
        1、时间线程马上进入执行状态,马上执行该时间线程run方法,可是由于此时lockObj变量所代表的对象锁被显示器线程持有,这时时间线程进入阻塞状态,显示器线程再次执行,然后执行sleep方法,显示器线程在继续持有对象锁的前提下也进入阻塞状态,60秒后显示器线程进入执行状态,随后显示器线程结束,对象锁被释放,进而时间线程开始执行,进而这行代码运行;
         2、时间线程并没有马上进入执行状态,显示器线程执行sleep方法,显示器线程在继续持有对象锁的前提下也进入阻塞状态,此时时间线程进入执行状态,执行该时间线程run方法,执行该方法中第一行输出代码,可是由于此时lockObj变量所代表的对象锁被显示器线程持有,所以时间线程并没有执行时间线程run方法内临界区中的代码,这时时间线程也进入阻塞状态,此时显示器和时间两条线程均进去阻塞状态,等待少于60秒的时间后,显示器线程进入运行状态,随后显示器线程结束,对象锁被释放,进而时间线程开始执行,进而这行代码运行;

此时临界区中的代码无法实现串行执行,因为此时对象锁在线程1和线程2之间不共享

此时临界区中的代码依然无法实现串行执行,因为每一个独立线程拥有一个独立的对象锁——new CounterThread()。
要明白这两点:
谁调用该run方法?——CounterThread类对象;
谁执行该run方法?——正在执行的线程

此时临界区中的代码可以实现串行执行,因为此时接口实现类对象充当了对象锁的功能,该对象锁在两个线程之间共享。

四、synchronized关键字

synchronized同步关键字有两种使用方式:
1、声明同步方法:

2、同步代码块:

五、死锁

1、如果有两个或两个以上的线程都访问了多个资源,而这些线程占用了一些资源的同时又在等待其它线程占用的资源,也就是说多个线程之间都持有了对方所需的资源,而又相互等待对方释放的资源,在这种情况下就会出现死锁。

2、多个线程互相等待对方释放对象锁,此时就会出现死锁

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Qt中,线程通讯可以使用共享内存来实现共享内存是一种跨进程共享数据的机制,可以在不同的线程传递数据。 Qt提供了QSharedMemory类来操作共享内存。下面是一个使用共享内存进行线程通讯的示例: ```cpp // 创建一个共享内存对象 QSharedMemory sharedMemory; // 设置共享内存的名称 sharedMemory.setKey("MySharedMemory"); // 在一个线程中写入数据到共享内存 if (sharedMemory.create(1024)) { sharedMemory.lock(); char* data = static_cast<char*>(sharedMemory.data()); // 在这里写入数据到共享内存 // 注意:要确保多个线程共享内存的访问是互斥的,可以使用QMutex来实现互斥访问 sharedMemory.unlock(); } // 在另一个线程中读取共享内存中的数据 if (sharedMemory.attach()) { sharedMemory.lock(); char* data = static_cast<char*>(sharedMemory.data()); // 在这里读取共享内存中的数据 sharedMemory.unlock(); sharedMemory.detach(); } ``` 在上面的示例中,我们创建了一个名为"MySharedMemory"的共享内存对象,并设置了它的大小为1024字节。然后,在一个线程中写入数据到共享内存中,另一个线程则可以读取共享内存中的数据。 需要注意的是,在多个线程共享内存进行读写时,需要确保访问的互斥性,以避免数据竞争。可以使用QMutex或其他同步机制来实现互斥访问。 另外,还可以使用信号与槽机制来实现线程的通讯。Qt提供了QObject::moveToThread()方法,可以将一个QObject对象移动到指定的线程中,从而实现线程的信号与槽的连接。这种方式相对于共享内存来说更加方便和安全。 希望以上信息能对你有帮助!如果还有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值