当前位置: 首页 > news >正文

电脑系统做的好的网站好/百度云搜索引擎入口

电脑系统做的好的网站好,百度云搜索引擎入口,佛山建网站,南山网站设计电话线程同步 基本概念 线程同步指的是在多线程环境下,通过某种机制来协调多个线程对共享资源的访问,确保在同一时刻只有一个线程能够访问共享资源,从而避免数据不一致和其他并发问题。可以将其类比为多个线程在使用同一台打印机,为…

线程同步

基本概念

线程同步指的是在多线程环境下,通过某种机制来协调多个线程对共享资源的访问,确保在同一时刻只有一个线程能够访问共享资源,从而避免数据不一致和其他并发问题。可以将其类比为多个线程在使用同一台打印机,为了避免打印内容混乱,需要规定一次只能有一个线程使用打印机,这个规定的过程就是线程同步。

存在以下问题

  • 一个线程持有锁会导致其他所有需要此锁的线程挂起。
  • 在多线程竞争下,加锁、释放锁会导致比较多的上下文切换和调度延时,引起性能问题。
  • 如果一个优先级高的线程等待一个优先级低的线程释放锁,会导致优先级倒置,引起性能问题。

产生问题的原因

当多个线程同时访问和修改共享资源时,可能会出现以下问题:

  • 数据不一致:例如,一个线程正在读取共享变量的值,而另一个线程同时在修改这个变量的值,就可能导致读取到的数据是错误的。
  • 竞态条件:多个线程对共享资源的操作顺序不确定,可能会导致程序的执行结果出现不可预测的情况。

实现线程同步的方式

1.synchronized 关键字(本质利用队列和锁)
  • 修饰实例方法:当 synchronized 修饰实例方法时,同一时刻只有一个线程能够访问该方法所属对象的这个方法。锁对象是当前对象实例。(一般是修饰那些会修改共享资源的方法,其他只读的方法可以不用修饰)

“锁对象是当前对象实例”,这句话的意思是把当前这个对象实例上锁,操作这个对象都要有锁才行,当有线程对这个对象进行操作时,这个对象就被锁上了,只有等这个线程结束操作这个对象才会释放锁,别的线程才能够对这个对象进行操作。

class Counter {private int count = 0;public synchronized void increment() {count++;}public int getCount() {return count;}
}

在上述代码中,increment() 方法被 synchronized 修饰,当一个线程进入该方法时,会自动获取 Counter 对象的锁,其他线程必须等待该线程执行完方法并释放锁后才能进入。

  • 修饰静态方法:如果 synchronized 修饰的是静态方法,那么锁对象是该类的 Class 对象。所有线程在访问该静态方法时,都需要竞争同一个锁。

回想之前的线程休眠,是不是提到过:"每一个对象都有一个锁,sleep不会释放锁“,这句话的意思就是假设a线程占领了这个锁,就算此时a线程调用sleep方法休眠了,但是由于锁没有释放,其他需要该锁的线程仍然不能执行。

class StaticCounter {private static int count = 0;public static synchronized void increment() {count++;}public static int getCount() {return count;}
}

这里的 increment() 静态方法被 synchronized 修饰,所有线程调用该方法时都要竞争 StaticCounter 类的锁。

  • 修饰代码块:可以指定一个对象作为锁,只有获取到该对象锁的线程才能执行代码块中的内容。

当使用 synchronized 修饰实例方法时,锁的对象是当前对象实例(this);修饰静态方法时,锁的对象是类的 Class 对象。如果共享资源不属于当前对象实例或者类,而是其他对象的数据,使用 synchronized 修饰方法可能无法达到预期的同步效果,因为此时锁错了对象。而修饰代码块可以自己指定锁的对象。

例如,有两个类 AB,类 B 中有一个共享资源,而类 A 中的方法需要操作类 B 的这个共享资源。如果在类 A 的方法上加 synchronized,锁的是类 A 的实例对象,而不是类 B 的实例对象,其他线程仍然可以同时操作类 B 的共享资源,无法实现同步。

class B {int sharedResource = 0;
}class A {B b;public A(B b) {this.b = b;}// 错误示例:锁的是A的实例对象,但是我们其实操作的共享数据是B类里面的,无法对B的共享资源同步,public synchronized void wrongModify() {b.sharedResource++;System.out.println(b.sharedResource);}// 正确示例:使用synchronized代码块,锁B的实例对象// 其实区别不大,就是把原来修饰方法的synchronized关键字,放到方法内部去修饰块,而块里的内容就是原来方法体里的代码,只是主要把要锁的对象给synchronized关键字public void correctModify() {synchronized (b) {b.sharedResource++;System.out.println(b.sharedResource);}}
}public class Main {public static void main(String[] args) {B b = new B();A a = new A(b);// 创建两个线程调用wrongModify方法,无法同步Thread t1 = new Thread(() -> {for (int i = 0; i < 1000; i++) {a.wrongModify();}});Thread t2 = new Thread(() -> {for (int i = 0; i < 1000; i++) {a.wrongModify();}});// 创建两个线程调用correctModify方法,可以同步Thread t3 = new Thread(() -> {for (int i = 0; i < 1000; i++) {a.correctModify();}});Thread t4 = new Thread(() -> {for (int i = 0; i < 1000; i++) {a.correctModify();}});t1.start();t2.start();t3.start();t4.start();}
}

在上述代码中,wrongModify 方法使用 synchronized 修饰,锁的是 A 的实例对象,无法对 B 的共享资源进行同步;而 correctModify 方法使用 synchronized 代码块,锁的是 B 的实例对象,可以实现对 B 的共享资源的同步访问。

2.ReentrantLock(可重入锁)
  • 简介ReentrantLockjava.util.concurrent.locks 包下的一个类,它是一个可重入的互斥锁,功能与 synchronized 类似,但提供了更灵活的锁机制。是显式的加锁,看起来更好理解。
  • 使用方式:
    • 加锁与解锁:通过 lock() 方法获取锁,unlock() 方法释放锁。为确保锁最终能被释放,通常将 unlock() 方法放在 finally 块中。
    • 可中断锁:支持可中断的锁获取模式,通过 lockInterruptibly() 方法实现,当线程在等待锁的过程中可以被中断。
    • 尝试获取锁:使用 tryLock() 方法可以尝试获取锁,如果锁可用则获取并返回 true,否则返回 false,不会阻塞线程。
  • 示例代码
package com.demo01;import java.util.concurrent.locks.ReentrantLock;public class ThreadLock {public static void main(String[] args) {station station = new station();// 开启三个线程new Thread(station).start();new Thread(station).start();new Thread(station).start();}
}
class station implements Runnable {private int ticketNumes = 10;private final ReentrantLock lock = new ReentrantLock();@Overridepublic void run() {while(true) {try{lock.lock();if(ticketNumes > 0) {System.out.println(ticketNumes--);Thread.sleep(1000);}else{break;}} catch (InterruptedException e) {throw new RuntimeException(e);}finally {lock.unlock();}}}
}
  1. 整体架构ThreadLock 类的 main 方法作为程序入口,创建 station 类实例并启动三个线程,让它们共享该实例执行售票任务。
  2. station:实现 Runnable 接口,包含车票数量 ticketNumesReentrantLock 类型的锁 lock
  3. run 方法逻辑
    • 进入无限循环,先调用 lock.lock() 获取锁,保证同一时刻只有一个线程能执行后续操作。
    • 检查车票数量,若大于 0 则打印车票号并减 1,模拟售票,线程休眠 1 秒模拟处理时间。
    • 若车票售罄,跳出循环结束线程。
    • 无论是否异常,在 finally 块调用 lock.unlock() 释放锁,确保锁资源正确释放。

注意事项:

在这段代码中,ReentrantLocklock 方法锁的不是传统意义上类似 synchronized 中隐式的 this 对象,它锁的是创建的 ReentrantLock 实例 lock 本身所代表的锁资源。所以当锁(即ReentrantLock lock)已经被其他线程持有时,当前线程会被阻塞,进入等待状态。它会一直等待,直到持有锁的线程释放锁,然后当前线程才有机会获取到锁并继续执行后续代码。

Lock 锁的加锁 lock() 方法和解锁 unlock() 方法一般和 try{} catch{} finally{} 语句块一起使用,这样不管是否有异常发生,都能保证在加锁后,即使在临界区代码执行过程中抛出异常,也可以在 finally 块中调用 unlock() 方法来释放锁,避免因异常导致锁无法释放而造成死锁,从而确保其他线程能够正常获取该锁并继续执行后续操作。

http://www.lryc.cn/news/577570.html

相关文章:

  • 如何做网站的seo/石家庄seo外包的公司
  • 珠宝类网站建设可执行报告/搜索引擎优化的主题
  • 网站划分栏目/郑州手机网站建设
  • 资源网站模板/百度账号客服
  • 云南建设监理协会网站/谷歌浏览器安卓版
  • 网站建设大赛策划书/海阳seo排名优化培训
  • 帮人做钓鱼网站/如何在各大网站发布信息
  • 网站更换服务器 备案/泉州seo按天收费
  • 北京海淀区是几环/重庆seo网站推广费用
  • 河北网站建设团队/电商网站建设
  • 百度上做网站/官方百度app下载安装
  • 注册域名的官方网站/软文推广一般发布在哪些平台
  • 24小时学会网站建设pdf/关键词吉他谱
  • 做外贸需要网站/西安网站建设排名
  • 合肥建站公司有哪家招聘的/百度seo代理
  • 贵州网站建设价格/怎么做盲盒
  • 网站前端培训/网站建设报价明细表
  • 杭州做网站博客/厦门搜索引擎优化
  • 南通优普网站建设制作/河南网站seo
  • 做网站难学吗/seo应该怎么做
  • 咸宁 网站建设/网站查询站长工具
  • 中国企业网官方网站查询/天津网站策划
  • wordpress果酱/seo网站推广报价
  • 深圳住房和建设局官网站/网址大全导航
  • cms三合一网站源码/运营网站
  • 做的网站响应速度慢/网站快照优化公司
  • 如何进行网站备案/怎么做私人网站
  • 天津网站建设制作开发公司/企业网站seo优化
  • 深圳做网站做公司网站的公司/seo 工具分析
  • 在线a视频网站一级a做爰/广东疫情防控措施