网站建设播放vr视频教程北京seo排名
news/
2025/10/3 5:44:36/
文章来源:
网站建设播放vr视频教程,北京seo排名,品牌营销策划有限公司,哪个做公司网站点击上方☝SpringForAll社区 轻松关注#xff01;及时获取有趣有料的技术文章本文来源#xff1a;https://www.cnblogs.com/ITtangtang/p/7602363.html一、线程安全性定义#xff1a;多个线程之间的操作无论采用何种执行时序或交替方式#xff0c;都要保证不变性条件不被破… 点击上方☝SpringForAll社区 轻松关注及时获取有趣有料的技术文章本文来源https://www.cnblogs.com/ITtangtang/p/7602363.html一、线程安全性定义多个线程之间的操作无论采用何种执行时序或交替方式都要保证不变性条件不被破坏“共享”变量可以由多个线程同时访问“可变”变量的值在其生命周期内可以发生改变如果当多个线程访问同一个可变的状态变量时没有使用合适的同步那么程序将会出现错误。有三种方式可以修复该问题不在线程之间共享该变量。将状态变量修改为不可变的变量。在访问状态变量时使用同步。竞态条件最常见的类型就是“先检查后执行”操作即通过一个可能失效的观测接口来决定下一步的动作。二、线程启动 继承Thread类重写里面的run方法用start方法启动线程 实现Runnable接口实现里面的run方法用new Thread(Runnable target).start()方法来启动start()和run()线程的启动并不是简单的调用了run方法,而是由一个线程调度器来分别调用所有线程的run方法,普通的run方法如果没有执行完是不会返回的,也就是会一直执行下去,这样run方法下面的方法就不可能会执行了,可是线程里的run方法却不一样,它只有一定的CPU时间,执行过后就给别的线程了,这样反复的把CPU的时间切来切去,因为切换的速度很快,所以我们就感觉是很多线程在同时运行一样(01) mythread.run()是在“主线程main”中调用的该run()方法直接运行在“主线程main”上。(02) mythread.start()会启动“线程mythread”“线程mythread”启动之后会调用run()方法此时的run()方法是运行在“线程mythread”上。http://blog.csdn.net/xuxurui007/article/details/7685076三、线程同步synchronized关键字内置锁(互斥锁):在java中每一个对象有且仅有一个同步锁。这也意味着同步锁是依赖于对象而存在。线程在进入同步代码块之前会自动获得锁并且在退出同步代码块时自动释放锁。同一时间最多只有一个线程持有该锁,其他线程必须等待或者阻塞直到该线程释放锁。如果持有锁的时间过长将会带来性能问题。实例锁 -- 锁在某一个实例对象上。如果该类是单例那么该锁也具有全局锁的概念。实例锁对应的就是synchronized关键字。全局锁 -- 该锁针对的是类无论实例多少个对象那么线程都共享该锁。全局锁对应的就是static synchronized(或者是锁在该类的class或者classloader对象上)。volatile变量volatile相当于synchronized的弱实现也就是说volatile实现了类似synchronized的语义却又没有锁机制。它确保对volatile字段的更新以可预见的方式告知其他的线程。volatile包含以下语义 (1)Java 存储模型不会对valatile指令的操作进行重排序这个保证对volatile变量的操作时按照指令的出现顺序执行的。 (2)volatile变量不会被缓存在寄存器中(只有拥有线程可见)或者其他对CPU不可见的地方每次总是从主存中读取volatile变量的结果。也就是说对于volatile变量的修改其它线程总是可见的并且不是使用自己线程栈内部的变量。也就是在happens-before法则中对一个valatile变量的写操作后其后的任何读操作理解可见此写操作的结果。尽管volatile变量的特性不错但是volatile并不能保证线程安全的也就是说volatile字段的操作不是原子性的volatile变量只能保证可见性(一个线程修改后其它线程能够理解看到此变化后的结果)要想保证原子性目前为止只能加锁四、线程协作线程等待等待的原因可能是如下几种情况(1)sleep() 的作用是让当前线程休眠即当前线程会从“运行状态”进入到“休眠(阻塞)状态”。sleep()会指定休眠时间线程休眠的时间会大于/等于该休眠时间在线程重新被唤醒时它会由“阻塞状态”变成“就绪状态”从而等待cpu的调度执行。(2)通过调用join()方法使线程挂起使自己等待另一个线程的结果直到另一个线程执行完毕为止。(3)通过调用wait()方法使线程挂起直到线程得到了notify()和notifyAll()消息线程才会进入“可执行”状态。(4)yield()的作用是让步。它能让当前线程由“运行状态”进入到“就绪状态”从而让其它具有相同优先级的等待线程获取执行权但是并不能保证在当前线程调用yield()之后其它具有相同优先级的线程就一定能获得执行权也有可能是当前线程又进入到“运行状态”继续运行注意 (01) wait()是让线程由“运行状态”进入到“等待(阻塞)状态”而yield()是让线程由“运行状态”进入到“就绪状态”。 (02) wait()是会让线程释放它所持有对象的同步锁而yield()方法不会释放锁。 (03) sleep()使当前线程暂停执行一段时间从而让其他线程有机会继续执行但它并不释放对象锁wait() “当前线程”在调用wait()时必须拥有该对象的同步锁。该线程调用wait()之后会释放该锁然后一直等待直到“其它线程”调用对象的同步锁的notify()或notifyAll()方法。然后该线程继续等待直到它重新获取“该对象的同步锁”然后就可以接着运行wait()后面的代码。wait()的作用是让“当前线程”等待而“当前线程”是指正在cpu上运行的线程因此调用wait()方法必须在同步块或者同步方法中进行(synchronized块或者synchronized方法) wait的东西一定要notify吗不一定notify() notify() 执行该方法的线程唤醒在对象的等待池中等待的一个线程JVM从对象的等待池中随机选择一个线程把它转到对象的锁池中。使线程由阻塞队列进入就绪状态。notifyAll(): 当前的线程已经放弃对资源的占有通知所有的等待线程从wait()方法后的语句开始运行。这里要注意一点notify()和notifyAll()方法只是唤醒等待该对象的锁的线程并不决定哪个线程能够获取到锁. 举个简单的例子 假如有三个线程Thread1、Thread2和Thread3都在等待对象objectA的锁此时Thread4拥有对象objectA的锁当在Thread4中调用objectA.notify()方法之后Thread1、Thread2和Thread3只有一个能被唤醒。注意被唤醒不等于立刻就获取了objectA的锁假若在Thread4中调用objectA.notifyAll()方法则Thread1、Thread2和Thread3三个线程都会被唤醒至于哪个线程接下来能够获取到objectA的锁就具体依赖于操作系统的调度了。 上面尤其要注意一点一个线程被唤醒不代表立即获取了对象的锁只有等调用完notify()或者notifyAll()并退出synchronized块释放对象锁后其余线程才可获得锁执行。首先wait()和notify(),notifyAll()是Object类的方法sleep()和yield()是Thread类的方法。 当然由于Thread类继承了Object类所以Thread也可以调用前面三个方法 由于每个对象都拥有锁所以让当前线程等待某个对象的锁当然应该通过这个对象来操作了。而不是用当前线程来操作因为当前线程可能会等待多个对象的锁如果通过线程来操作就非常复杂了。(1).常用的wait方法有wait()和wait(long timeout):void wait() 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前导致当前线程等待。void wait(long timeout) 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法或者超过指定的时间量前导致当前线程等待。wait()后线程会释放掉它所占有的“锁标志”从而使线程所在对象中的其它synchronized数据可被别的线程使用。wait()和notify()因为会对对象的“锁标志”进行操作所以它们必须在synchronized函数或synchronized block中进行调用。如果在non-synchronized函数或non-synchronized block中进行调用虽然能编译通过但在运 行时会发生IllegalMonitorStateException的异常。(2).Thread.sleep(long millis),必须带有一个时间参数。sleep(long)使当前线程进入停滞状态所以执行sleep()的线程在指定的时间内肯定不会被执行sleep(long)可使优先级低的线程得到执行的机会当然也可以让同优先级和高优先级的线程有执行的机会sleep(long)是不会释放锁标志的。(3).yield()没有参数。sleep 方法使当前运行中的线程睡眼一段时间进入不可运行状态这段时间的长短是由程序设定的yield 方法使当前线程让出CPU占有权但让出的时间是不可设定的。yield()也不会释放锁标志。实际上yield()方法对应了如下操作先检测当前是否有相同优先级的线程处于同可运行状态如有则把 CPU 的占有权交给此线程否则继续运行原来的线程。所以yield()方法称为“退让”它把运行机会让给了同等优先级的其他线程。sleep方法允许较低优先级的线程获得运行机会但yield()方法执行时当前线程仍处在可运行状态所以不可能让出较低优先级的线程些时获得CPU占有权。在一个运行系统中如果较高优先级的线程没有调用 sleep 方法又没有受到 I/O阻塞那么较低优先级线程只能等待所有较高优先级的线程运行结束才有机会运行。yield()只是使当前线程重新回到可执行状态所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。所以yield()只能使同优先级的线程有执行的机会。sleep和yield区别 1、sleep()方法会给其他线程运行的机会而不考虑其他线程的优先级因此会给较低线程一个运行的机会yield()方法只会给相同优先级或者更高优先级的线程一个运行的机会。 2、当线程执行了sleep(long millis)方法后将转到阻塞状态参数millis指定睡眠时间当线程执行了yield()方法后将转到就绪状态。 3、sleep()方法声明抛出InterruptedException异常而yield()方法没有声明抛出任何异常为什么notify(), wait()等函数定义在Object中而不是Thread中? Object中的wait(), notify()等函数和synchronized一样会对“对象的同步锁”进行操作。wait()会使“当前线程”等待因为线程进入等待状态所以线程应该释放它锁持有的“同步锁”否则其它线程获取不到该“同步锁”而无法运行那么notify()是依据什么唤醒等待线程的或者说wait()等待线程和notify()之间是通过什么关联起来的答案是依据“对象的同步锁”。 负责唤醒等待线程的那个线程(我们称为“唤醒线程”)它只有在获取“该对象的同步锁”(这里的同步锁必须和等待线程的同步锁是同一个)并且调用notify()或notifyAll()方法之后才能唤醒等待线程。虽然等待线程被唤醒但是它不能立刻执行因为唤醒线程还持有“该对象的同步锁”。必须等到唤醒线程释放了“对象的同步锁”之后等待线程才能获取到“对象的同步锁”进而继续运行。 总之notify(), wait()依赖于“同步锁”而“同步锁”是对象锁持有并且每个对象有且仅有一个这就是为什么notify(), wait()等函数定义在Object类而不是Thread类中的原因。ConditionCondition是在java 1.5中才出现的它用来替代传统的Object的wait()、notify()实现线程间的协作相比使用Object的wait()、notify()使用Condition的await()、signal()这种方式实现线程间协作更加安全和高效。因此通常来说比较推荐使用ConditionJava阻塞队列实际上是使用了Condition来模拟线程间协作。Condition是个接口基本的方法就是await()和signal()方法Condition依赖于Lock接口生成一个Condition的基本代码是lock.newCondition()调用Condition的await()和signal()方法都必须在lock保护之内就是说必须在lock.lock()和lock.unlock之间才可以使用 Conditon中的await()对应Object的wait() Condition中的signal()对应Object的notify() Condition中的signalAll()对应Object的notifyAll()。五、线程中断http://blog.csdn.net/dlite/article/details/4218105Java的线程调度不提供抢占式中断而采用协作式的中断。其实协作式的中断原理很简单就是轮询某个表示中断的标记。通常我们通过“标记”方式终止处于“运行状态”的线程。其中包括“中断标记”和“额外添加标记”。(01) 通过“中断标记”终止线程。 形式如下1Override2publicvoid run() {3 while (!isInterrupted()) {4 // 执行任务... }5}说明isInterrupted()是判断线程的中断标记是不是为true。当线程处于运行状态并且我们需要终止它时可以调用线程的interrupt()方法使用线程的中断标记为true即isInterrupted()会返回true。此时就会退出while循环。注意interrupt()并不会终止处于“运行状态”的线程它会将线程的中断标记设为true。(02) 通过“额外添加标记”。 形式如下 1private volatile boolean flag true; 2protected void stopTask() { 3 flag false; 4} 5 6Override 7public void run() { 8 while (flag) { 9 // 执行任务... }10}说明线程中有一个flag标记它的默认值是true并且我们提供stopTask()来设置flag标记。当我们需要终止该线程时调用该线程的stopTask()方法就可以让线程退出while循环。注意将flag定义为volatile类型是为了保证flag的可见性。即其它线程通过stopTask()修改了flag之后本线程能看到修改后的flag的值。通常我们通过“中断”方式终止处于“阻塞状态”的线程。当线程由于被调用了sleep(), wait(), join()等方法而进入阻塞状态若此时调用线程的interrupt()将线程的中断标记设为true。由于处于阻塞状态中断标记会被清除同时产生一个InterruptedException异常。将InterruptedException放在适当的为止就能终止线程1Override2public void run() {3 try {4 while (true) {5 // 执行任务... }6 } catch (InterruptedException ie) { 7 // 由于产生InterruptedException异常退出while(true)循环线程终止 }8}注意对InterruptedException的捕获务一般放在while(true)循环体的外面这样在产生异常时就退出了while(true)循环。参考资料http://www.cnblogs.com/jobs/archive/2010/07/29/1788156.html梁飞Java并发编程常识.pptx● Kafka基本架构及原理● JVM基础● 数据仓库Mysql大量数据快速导出● 深入理解Java注解● 深入理解Java类加载机制及反射● Java 如何设计 API 接口实现统一格式返回● 图文你女朋友也能看懂的 Kubernetes ● 打开黑盒从 MySQL 架构设计出发看它是如何执行一条 SQL 语句的● 记一次神奇的 sql 查询经历group by 慢查询优化● 花了一个月时间梳理了一下公司的微服务核心架构原来也不是太难.● 一次900万数据量的 SQL 查询优化分析【上百倍性能优化】● 缓存穿透、缓存并发、缓存失效之思路变迁● 花了一个月时间梳理了一下公司的微服务核心架构原来也不是太难.● 一文详解微服务架构● API规范约定
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/925566.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!