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

网站制作产品优化软件开发文档编写规范

网站制作产品优化,软件开发文档编写规范,搜索关键字搜索到网站,温州网站设计制作꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好#xff0c;我是xiaoxie.希望你看完之后,有不足之处请多多谅解#xff0c;让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如需转…  ꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好我是xiaoxie.希望你看完之后,有不足之处请多多谅解让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如需转载还请通知˶⍤⃝˶​个人主页xiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 系列专栏:xiaoxie的JAVAEE学习系列专栏——CSDN博客●ᴗσσணღ我的目标:团团等我( ◡̀_◡́ ҂)  ( ⸝⸝⸝›ᴥ‹⸝⸝⸝ )欢迎各位→点赞 收藏⭐️ 留言​关注互三必回!  一.线程等待机制 1.什么是线程等待机制 线程等待机制是多线程编程中用于同步线程执行流程的一种技术它允许一个线程暂停执行即进入等待状态直到满足特定条件或其他线程发送一个通知信号为止。在Java以及许多其他支持多线程的语言中这种机制通常通过以下方式实现 1.wait() 方法 wait() 是 java.lang.Object 类的一个方法当在一个对象上调用 wait() 时当前线程必须首先获得该对象的监视器即锁。调用后线程会释放对象的锁并进入等待状态直到被其他线程通过调用 notify() 或 notifyAll() 方法唤醒。 2.notify() 和 notifyAll() 方法 notify() 唤醒在此对象监视器上等待的一个单个线程。notifyAll() 唤醒在此对象监视器上等待的所有线程。 2.wait() 方法和join()方法和sleep()方法的区别 我们都知道wait() 方法和join()方法和sleep()方法都是控制线程行为的方法那么它们之间有什么区别吗? wait() 方法 属于 java.lang.Object 类的方法必须在 synchronized 代码块或方法中调用因为它依赖于对象的监视器锁。当调用 wait() 时当前线程会释放所持有的对象监视器锁并进入等待状态直到其他线程调用同一对象上的 notify() 或 notifyAll() 方法将其唤醒。wait() 方法主要用于线程间同步与通信它使得线程能够有条件地等待资源就绪。 join() 方法 属于 java.lang.Thread 类的实例方法用于让当前线程等待调用该方法的目标线程终止。当调用 t.join() 时当前线程将阻塞直到线程 t 完成它的任务。join() 有助于实现线程间的顺序执行比如主线程等待子线程完成后再继续执行。 sleep() 方法 也是 java.lang.Thread 类的静态方法但它并不涉及线程间的交互和同步。sleep(long millis) 会让当前线程暂时停止执行一段时间这段时间内线程不会消耗CPU资源但仍保持“活着”的状态。sleep() 方法调用期间线程不会释放已经获取的任何锁资源。主要用于模拟延迟或防止繁忙循环消耗过多CPU资源。 总结起来 1.wait() 是一种协调机制用于线程间通信和同步会释放锁并阻塞线程直到收到通知。 2.join() 用于线程顺序控制让一个线程等待另一个线程结束同样会阻塞当前线程但不涉及锁的管理。 3.sleep() 是简单的线程暂停机制仅影响单个线程的行为用于暂停一定时间不涉及线程间的通信和锁的状 3.线程等待机制的代码案例 题目要求:有三个线程分别只能打印AB和C要求按顺序打印ABC打印10次 // 创建一个演示类Demo1 public class Demo1 {// 定义一个共享静态变量count用于记录循环次数public static int count;// 程序主入口public static void main(String[] args) throws InterruptedException {// 创建一个共享的对象locker作为线程间的同步锁Object locker new Object();// 创建线程t1循环10次每次检查count是否能被3整除不能则等待能则输出当前线程名、增加count并唤醒所有等待线程Thread t1 new Thread(() - {for (int i 0; i 10; i) {synchronized (locker) { // 对locker对象进行同步while (count % 3 ! 0) { // 如果count不是3的倍数try {locker.wait(); // 当前线程等待释放locker锁} catch (InterruptedException e) {throw new RuntimeException(e); // 处理中断异常}}System.out.print(Thread.currentThread().getName()); // 输出当前线程名count; // 增加count值locker.notifyAll(); // 唤醒所有等待locker锁的线程}}}, A);// 创建线程t2逻辑与t1类似但检查count是否为3的倍数加1Thread t2 new Thread(() - {for (int i 0; i 10; i) {synchronized (locker) {while (count % 3 ! 1) {try {locker.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.print(Thread.currentThread().getName());count;locker.notifyAll();}}}, B);// 创建线程t3逻辑与t1类似但检查count是否为3的倍数加2Thread t3 new Thread(() - {for (int i 0; i 10; i) {synchronized (locker) {while (count % 3 ! 2) {try {locker.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println(Thread.currentThread().getName()); // 输出当前线程名并换行count;locker.notifyAll();}}}, C);// 启动三个线程t1.start();t2.start();t3.start();// 主线程休眠1秒以便给其他线程运行机会Thread.sleep(1000);} } 输出结果: 在上述代码中线程 t1、t2 和 t3 分别会在满足各自条件时输出相应内容并更新 count 变量。具体过程如下 当 t1 获取到 locker 锁后会检查 count 是否为3的倍数。如果不是则释放锁并调用 wait() 进入等待状态。此时t1 不再占用锁t2 和 t3 就有机会竞争锁。 若 t2 或 t3 其中之一成功获取锁并满足自己的条件即 count 为3的倍数加1或2则会输出相应的线程名并增加 count 的值然后调用 notifyAll() 唤醒所有等待 locker 锁的线程。 被唤醒的线程会重新开始尝试获取锁并再次进入 while 循环检查条件。即使由于“虚假唤醒”被唤醒由于采用了 while 循环而非 if线程也会在未满足条件时继续等待从而确保了正确的执行逻辑。 如此反复直到 count 达到10*330所有线程完成各自的循环整个程序结束。在此过程中线程间通过 wait() 和 notifyAll() 实现了同步与协作确保了线程按序交替执行并共同维护了对 count 变量的正确更新(count操作是在锁内部完成的,不会出现内存可见性问题)。 注意:这里还有一个小知识点就是这里的条件判断为什么要用 while 而不是用 if? 1.多线程环境下即使满足某个条件后调用了 wait() 方法线程被唤醒时并不能保证条件依然成立。这是因为 notify() 或 notifyAll() 方法只会唤醒一个或所有等待的线程但并不会立即恢复它们的执行而是需要重新竞争锁资源。如果在当前线程被唤醒并重新获取锁之前有其他线程改变了共享资源如 count 变量那么之前满足的条件可能不再满足。 2.为了确保线程安全在进入临界区后使用 while 循环不断检查条件是一种最佳实践这被称为“循环等待-通知”模式。只有当条件确实满足时线程才会退出循环并执行后续操作否则将继续等待直到其他线程改变条件并再次唤醒它。这样可以防止出现“虚假唤醒”的问题提高程序的健壮性。 3.当线程调用 wait() 方法时它会释放锁并进入等待状态直到被其他线程唤醒或者等待超时。然而操作系统可能会出于效率或者其他因素例如定时器精度、系统调度策略等无预期地唤醒等待中的线程。尽管这种情况在实践中并不常见但它是合法的标准并未禁止此类行为。 为了避免虚假唤醒导致的错误逻辑执行编程时推荐采用循环检查条件的方式来调用 wait() 方法而不是简单地使用 if 判断之后立即调用 wait()。 4.为什么要使用wait()方法和notify()方法 使用 wait() 和 notify() 方法的必要性和应用场景主要包括以下几点 必要性 线程同步与协作在多线程环境中当多个线程共享资源并且需要按照某种特定顺序或条件进行操作时wait() 和 notify() 方法是必要的。例如在生产者-消费者问题中生产者线程需要在缓冲区满时等待消费者线程在缓冲区空时等待两者都需要对方操作后才能继续执行这就需要用到 wait() 和 notify() 来进行线程间的有效沟通。避免资源竞争与死锁通过适时地释放锁并进入等待状态线程能够有效地避免资源的竞争减少死锁发生的可能性。性能优化相比不断地轮询检查条件是否满足称为“忙等待”wait() 方法可以让线程在等待条件变化时释放CPU从而节省系统资源。 应用场景 生产者-消费者模型生产者线程负责生成数据放入共享容器当容器满时生产者调用 wait() 方法等待消费者线程从容器中取出数据消费当容器空时消费者调用 wait() 方法等待。一旦数据产生或消耗对应的线程会调用 notify() 方法唤醒等待的线程。资源池管理在资源池达到最大限制时请求新资源的线程会被阻塞直到有线程归还资源后通过 notify() 触发等待线程继续执行。信号量控制在复杂的并发场景中可以通过 wait() 和 notify() 控制多个线程在多个资源之间按需分配和回收。 总之wait() 和 notify() 方法是在多线程编程中实现高效、安全线程间通信的核心工具它们解决了线程间的同步问题使得不同线程可以根据预设条件有序地进行工作极大地提高了程序设计的灵活性和并发效率。不过需要注意的是使用这两个方法时应当遵循特定的准则如必须在同步代码块或同步方法中调用同时还要警惕死锁和其他并发问题的发生。在现代Java编程中java.util.concurrent 包提供的高级并发工具如 Semaphore、BlockingQueue(阻塞队列)、CountDownLatch 等往往更加易于理解和使用但了解底层的 wait() 和 notify() 工作原理仍然具有重要意义。 二.死锁(面试常考) 1.什么是死锁 死锁是指在多线程或多进程环境下两个或多个进程或线程在执行过程中因争夺资源而造成的一种互相等待的现象若无外力干涉它们都无法向前推进即完成各自的任务。具体地说每个进程都至少占有一个资源并且正在等待另一个进程中占有的资源被释放然而这个资源又正被等待它释放资源的进程所占有形成了一个环形等待链这样每个进程都在等待别的进程释放资源从而陷入了一个永久的停滞状态。 2.MySql的死锁问题(也是面试常考) 这里既然提到了死锁问题,博主就顺便也简单说明一下MySql的死锁问题吧 MySQL数据库中的死锁Deadlock指的是两个或多个事务在执行过程中由于对相同资源请求不同的锁定顺序彼此互相等待对方释放锁定资源从而形成的一种循环等待状态导致事务无法正常执行下去。 MySQL中的死锁主要发生在并发事务处理过程中当两个或多个事务尝试以不同的顺序锁定相同的资源时可能发生。例如 事务A锁定了记录R1并试图锁定记录R2与此同时事务B已经锁定了记录R2并尝试锁定记录R1由于事务A持有R1的锁所以事务B无法获得R1的锁而事务B持有R2的锁事务A也无法获得R2的锁因此两个事务都进入了等待对方释放资源的状态形成了死锁。 MySQL处理死锁的方式包括 自动检测与解决: MySQL的InnoDB存储引擎具有死锁检测机制定期检查是否存在死锁并在检测到死锁时自动回滚其中一个事务使其他事务得以继续执行。 预防死锁 设计应用程序时确保事务尽可能短小减少事务锁定资源的时间。确保事务对资源的锁定顺序一致例如按照相同的索引顺序访问表。适当设置事务的隔离级别虽然较低的隔离级别如读已提交可以减少死锁的可能性但也可能导致更多的并发问题如不可重复读或幻读。 手动解决 当遇到死锁时DBA可以手动分析并决定是否应该杀死其中一个或多个事务以打破死锁循环。 应用层处理 在应用程序设计层面可以通过添加重试机制来应对可能出现的死锁当事务因死锁被回滚时应用层可以捕获异常并重新发起事务。 配置调整 调整数据库相关的参数如增大innodb_lock_wait_timeout当等待锁的时间超过设定阈值时事务将自动回滚从而避免无限期等待。 综上所述MySQL中的死锁问题需要结合数据库服务器的内部机制和应用程序的设计来进行综合考虑和处理。 当然MySQL的死锁问题有很多细节值得深入探讨和扩展下面是一些额外的点 1.死锁的检测与处理 死锁检测算法InnoDB存储引擎使用了一种基于等待图的死锁检测算法。每当事务请求新的锁时都会检查是否存在循环等待的情况。如果有InnoDB会选择牺牲rollback一个事务以打破死锁。 innodb_deadlock_detect 参数MySQL可以通过配置 innodb_deadlock_detect 参数来控制是否启用死锁检测功能。默认情况下此参数为ON表示InnoDB会积极检测死锁并在发现死锁时立即回滚一个事务。但是关闭此选项意味着系统在等待锁超时后才有可能检测到死锁。 innodb_lock_wait_timeout这是一个影响死锁处理的重要参数它指定了一个事务在等待锁时可以等待的最大时间单位秒。超时后事务将被回滚并抛出一个错误客户端可以根据错误代码识别死锁并选择合适的重试策略。 2.死锁的预防策略 严格的事务顺序在编写事务时尽量保持固定的资源获取顺序避免交叉锁定资源引起死锁。 最小化锁定范围只锁定那些真正需要修改的数据避免不必要的大范围锁定。 合理设置事务隔离级别尽管较低的隔离级别减少了死锁的风险但可能引入其他并发问题。根据实际需求选择合适的事务隔离级别兼顾并发性能和一致性需求。 及时提交或回滚事务不要让事务长时间持有锁特别是在循环中逐条处理大量记录时应及时提交或回滚事务释放资源。 使用乐观锁或版本控制在某些场景下可以使用乐观锁如CAS操作或数据库的行版本控制机制MVCC这类机制在一定程度上降低了死锁发生的概率。 3.死锁监控与排查 SHOW ENGINE INNODB STATUS可以查看InnoDB引擎的状态其中包含有关最近发生的死锁的信息。 performance_schemaMySQL的性能模式包含了丰富的监控信息可以帮助开发者跟踪和诊断死锁的具体情况。 日志记录通过对MySQL错误日志的监控可以捕获到死锁相关的错误信息帮助定位问题。 3.Java中的死锁问题(面试常考) 1.死锁发生的必要条件(缺一不可) 互斥条件(锁的特性)至少有一个资源是不可共享的也就是说一段时间内仅允许一个进程使用。持有并等待条件已经获得了至少一个资源的进程还在等待获取其他资源而不会释放已持有的资源。非抢占条件(锁的特性)资源一旦被分配给一个进程就不能被强制性地从该进程中收回只能由进程自身主动释放。循环等待条件存在一个进程-资源的闭环链每个进程都在等待下一个进程所占用的资源,循环阻塞等待了。 2.出现死锁的几个经典场景(在多线程的环境下) 1.锁顺序不一致线程A按照顺序先锁定资源A再锁定资源B而线程B则是先锁定资源B再锁定资源A当两个线程同时执行时可能因资源获取顺序不同而导致死锁 Java代码 public class Demo2 {public static void main(String[] args) {Object lockerA new Object();Object lockerB new Object();Thread A new Thread(() - {synchronized (lockerA) {System.out.println(线程A获取锁A);try {Thread.sleep(100); // 模拟处理时间} catch (InterruptedException e) {e.printStackTrace();}synchronized (lockerB) {System.out.println(线程A获取锁B);}}});Thread B new Thread(() - {synchronized (lockerB) {System.out.println(线程B获取锁B);try {Thread.sleep(100); // 模拟处理时间} catch (InterruptedException e) {e.printStackTrace();}synchronized (lockerA) {System.out.println(线程B获取锁A);}}});A.start();B.start();} }2.资源分配不当假设线程A持有了资源R1并请求资源R2线程B持有了资源R2并请求资源R1这时线程A和线程B都将阻塞形成死锁。 Java代码: public class Demo3 {// 定义两种资源对象static class Resource {private String name;public Resource(String name) {this.name name;}Overridepublic String toString() {return Resource: name;}}public static void main (String[]args){// 创建资源R1和R2Resource r1 new Resource(R1);Resource r2 new Resource(R2);// 创建线程A和线程BThread threadA new Thread(() - {synchronized (r1) {System.out.println(Thread.currentThread().getName() 获取 r1);synchronized (r2) {System.out.println(Thread.currentThread().getName() 获取 r2);}}}, 线程A);Thread threadB new Thread(() - {synchronized (r2) {System.out.println(Thread.currentThread().getName() 获取 r2);synchronized (r1) {System.out.println(Thread.currentThread().getName() 获取 r1);}}}, 线程B);// 启动线程threadA.start();threadB.start();} } 3.经典的哲学家就餐问题五位哲学家围绕圆桌而坐每位哲学家有一只手拿筷子他们需要两只筷子才能就餐。当所有哲学家都拿起左边的筷子后大家都在等待右边筷子形成死锁。 4.死锁的解决方法 预防死锁 资源一次性分配一次性为进程分配所需的全部资源这样就可以避免循环等待条件。资源有序分配规定所有的进程都按照统一的顺序申请资源这样可以避免循环等待。破坏请求和保持条件要求进程在请求新资源之前释放已有资源或者在申请资源时不立即锁定资源而是等到可以一次性获得所有所需资源时才进行锁定。破坏不可剥夺条件允许资源抢占即当一个进程请求资源无法得到满足时系统可以剥夺已经分配给其他进程但尚未使用的资源。 避免死锁 动态分配资源时使用银行家算法等策略系统在分配资源前预先计算是否有足够的资源满足所有进程的安全序列以防止系统进入不安全状态从而避免死锁。 检测死锁 在系统中设置周期性的死锁检测机制通过算法如Wait-For Graph算法来发现死锁。当检测到死锁时采取一定的策略进行解除如选择一个进程取消回滚或撤销或者选择资源进行抢占。 解除死锁 撤销进程选择一个死锁进程进行回滚释放其所占用的资源使其余进程得以继续执行。资源剥夺强制从死锁进程手中剥夺部分资源分配给其他进程打破循环等待。 资源超时回收 设置资源请求的超时时间当请求超出指定时间仍未能获取资源时释放已持有资源然后重新发起请求这样可以避免长期等待和死锁。 每种方法都有其适用场景和局限性实际应用时需要根据系统的具体情况和性能要求选择合适的方法。在设计并发和多线程程序时良好的编程实践和精心设计的资源管理策略也是非常重要的例如尽量减少资源的持有时间、确保资源释放的完整性以及避免不必要的资源竞争。 以上就是关于线程安全问题的所以内容了,感谢你的阅读!
http://www.tj-hxxt.cn/news/137084.html

相关文章:

  • 网站备案换ip商丘软件开发
  • 官方网站下载抖音杭州专业做网站公司
  • wap网站开发多少钱网站可以做推广吗
  • c 网站开发环境wordpress主题广告
  • 云主机搭建asp网站wordpress用什么主机好
  • 什么网站代做毕业设计比较好如何免费做一个网页
  • 专做户外装备测评视频网站wordpress 页面 权限
  • 呼和浩特市网站公司电话安徽住房和建设厅网站
  • 网站开发生命周期商业网
  • 做基因检测网站网站轮播广告代码
  • 网站如何排名建设一个招聘网站的策划
  • 珠海做网站公司设计品牌企业logo
  • 飞沐网站建设北京惠州百度seo电话
  • 织梦网站怎么做伪静态数据分析师一般一个月多少钱
  • 如何免费创建一个自己的网站用dw制作个人简介网页步骤
  • 做网站电话销售说辞旅行社营业部管理办法
  • 景县网站建设公司外贸产品网站建设
  • 伪静态就是把网站地址一元购网站建设
  • 网站建设服务费入推广计划书怎么写
  • 销售型网站建设基本要素WordPress创建简码
  • 网站域名以co与com有什么不同网站做百度百科
  • 企业网站管理系统使用教程全国工厂的网站建设
  • 企业网站建设 阿里云wordpress禁止谷歌字体大小
  • 建站导航如何用vs做网站
  • 网站建设价格是哪些方面决定的部队网站建设方案
  • 门户型网站建设招商局网站建设方案
  • 旅行网站开发免费做网站页头图
  • 东莞做企业网站WordPress英文换行
  • 做网站的荣誉证书网络营销期末考试试题及答案
  • 万网网站域名注册2008 iis 添加 网站 权限设置权限