小奥的学习笔记

  • Home
  • Learning & Working
    • Speech Enhancement Notes
    • Programming language
    • Computer & DL
    • MOOC
  • Life
    • Life Time
    • Thinking & Comprehension
    • Volunteer
    • Plan
    • Travel
  • Footprints
  • GuestBook
  • About
    • About Me
    • 个人履历
    • 隐私策略
  1. 首页
  2. Study-notes
  3. Programming language
  4. Java
  5. 正文

Java语言程序设计(进阶)(第三章)整理

2018年3月30日 1471点热度 0人点赞 0条评论

第三章 线程(下)

3.1 线程安全与线程兼容与对立

线程安全:当多个线程访问同一个对象时,如果不同考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那这个对象是线程安全的。它包括:

(1)不可变。如果它访问的对象是不可修改的,那么它本身就是安全的。比如:

①final修饰:public final a =100;

②java.lang.String: String s = “String”;string常量

③枚举类型:public enum Color{RED,GREEN}

④java.lang.Number的子类,比如Long,Double

⑤BigInteger,BigDecimal(数值类型的高精度实现)

(2)绝对线程安全:满足上述定义的线程就为绝对县城安全,javaAPI标注自己是线程安全的类绝大多数不是绝对线程安全的。

(3)相对线程安全:通常意义上的线程安全,需要保证这个对象单独操作是线程安全的,调用的时候不需要做额外的保障措施,但是对于一些特定顺序的连续调用,就需要在调用时使用同步手段保证调用的正确性。如Vector,HashTable等。

(4)线程的兼容和对立。线程兼容指对象本身不是线程安全的,但是可以通过在调用端正确地使用同步手段来保证对象在并发环境中可以安全使用;线程对立是无论调用端是否采用了同步措施,都无法在多线程环境中并发使用的代码。

3.2 线程的安全实现——互斥同步

同步的互斥实现方式:临界区、互斥量、信号量 。解决的方式就是使用Synchronized关键字,经过编译后,会在同步块前后行程monitorenter和monitorexit两个字节码。synchronized同步块对自己是可重入的,不会将自己锁死;同步块在已进入的线程执行完之前,会阻塞后面其它线程的进入,以保证程序安全性。

还有一种方式是重入锁(java.util.concurrent)。相比采用synchronized,重入锁可实现:等待可中断、公平锁、锁可以绑定多个条件。Synchronized表现为原生语法层面的互斥锁,而RenentrantLock表现为API层面的互斥锁。

他们的性能比较如图1所示。

1522380739539240.jpg 

图1

3.3 线程的安全实现——非阻塞同步

1.阻塞同步:互斥同步存在的问题是进行线程阻塞和唤醒所带来的性能问题,这种同步称为阻塞同步。这是一种悲观并发策略。

2.非阻塞同步:不同于前者,它是基于冲突检测的乐观并发策略,就是先进行操作,如果没有其他线程征用共享数据,则操作成功;否则就是产生了冲突,采取不断重试直到成功为止的策略。这种策略不需要把线程挂起,称为非阻塞同步。

非阻塞同步使用硬件处理器指令进行不断重试策略:

①测试并设置(Test-and-Set);

②获取并增加(Fetch-and-Increment);

③交换(Swap);

④比较并交换(CAS);

⑤加载链接,条件存储(LL, SC)。

例如java实现类AtomicInteger,AtomicDouble等等。

例:非阻塞实例

代码:

class Counter{
       private volatile int count =0;
       public synchronized void increment(){
              count++;//若要线程安全执行count++,需要加锁
       }
       public int getCount(){
              return count;
       }
}

例:上例用AtomicInteger来改进

代码:

class Counter{
       private AtomicInteger int count =new AtomicInteger();
       public void increment(){
              count。incrementAndGet();
       }
       //使用AtomicInteger之后不需要加锁,也可以实现线程安全
       public int getCount(){
              return count.get();
       }
}

3.4 线程的安全实现——无同步方案

1.可重入代码:也叫纯代码。相对线程安全来说,可以保证线程安全。可以在代码执行过程中中断它,转而去执行另一段代码,而在控制权返回后,原来程序不会出现任何错误。

2.线程本地存储:如果一段代码所需数据必须与其它代码共享,那么看这些数据代码能否保证在同一个线程中执行,如果可以,就可以把共享数据的可见范围限定在同一个线程之内,这样无需同步也能保证线程之间不出现数据争用问题。

例:TthreadLocal——本地存储例子

代码:

public class SequenceNumber{
       //①通过匿名内部类覆盖ThreadLocal的initialValue()
       //方法指定初始值
       private static ThreadLocal<Integer>seqNum = 
       new ThreadLocal<Integer>(){
              public Integer initialValue(){
                     return 0;
              }
             
       };
       public int getNextNum(){
              //②获取下一个序列值
              seqNum.set(seqNum.get()+1);
              return seqNum.get();
       }
       public static void main(String[] args){
              SequenceNumber sn = new SequenceNumber();
              //③三个线程共享sn,各自产生序列号
              TestClient t1 = new TestClient(sn);
              TestClient t2 = new TestClient(sn);
              TestClient t3 = new TestClient(sn);
              t1.start();
              t2.start();
              t3.start();
       }
       private static class TestClient extends Thread{
              private SequenceNumber sn;
              public TestClient(SequenceNumber sn){
                     this.sn =sn;
              }
              public void run(){
                     for(int i=0;i<3;i++){
                            //④每个线程打出3个序列值
                      System.out.println("thread["+
                      Thread.currentThread().getName()+"]sn["
                      +sn.getNextNum()+"]");
                     }
              }
       }
}

程序分析:

seqNum利用一个匿名类来覆盖ThreadLocal里面的方法,直接返回0。第二个方法是通过刚刚定义完的变量get掉值然后加1,设置为新的值。

第三步利用后面产生的线程类,然后共享sn,start()方法各自产生序列号。下面的线程类表述了第三步是要干嘛。其实是把sn赋值给本类的sn,run()方法就是循环三遍,每一次都打印出线程名字和sn的值。

 

3.5 锁优化

它主要有这样几种优化方式:

1.自旋锁。互斥同步挂起线程和恢复线程都需要转入内核态中完成,这些操作给系统的并发性能带来很大压力。自旋锁就是,如果物理机器有一个以上处理器能够让两个或以上的线程同时并行执行,那么可以让后面请求所的线程等等,但不放弃处理器的执行时间,看看有锁的线程是否很快释放。为了让线程等待,可以让线程执行一个忙循环。java中自旋默认10次。

2.自适应锁:自适应自旋就是自旋时间不固定,而是由前一次在同一个锁上的自旋时间及锁拥有者的状态决定。如果在同一个锁对象上自旋等待刚刚成功获得锁,并且持有锁的线程正在运行中,那么虚拟机就会认为这次自旋也很有可能再次成功,进而它允许自旋等待相对时间更长一点。

3.锁消除:JVM即时编译器在运行时,对一些(代码要求同步,但是被检测到不可能存在共享数据竞争的锁)进行消除。

判定依据:如果判断在一段代码中,堆上的所有数据都不会逃逸出去从而被其它线程访问到,那就可以把他们当做栈上数据对待,认为他们是线程私有的,同步加锁自然无需进行。

4.锁粗化:如果一系列的连续操作都对同一个对象反复加锁,甚至加锁操作出现在循环体重,那么即使没有线程争用,频繁的进行互斥同步也会导致不必要的性能损耗,此时只需要将同步块范围扩大即可,即锁粗化。

5.偏向锁:它的目的是消除数据无竞争情况下的同步原语,进一步提高程序运行的性能。偏向锁就是在无竞争的情况下把整个同步都消除掉,连CAS(比较并交换)操作都不做。

偏向的意思是这个锁会偏向第一个获得它的线程,如果接下来的执行中,该锁没有被其它线程获取,则持有偏向锁的线程永远不需要再进行同步。

本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: Java
最后更新:2018年3月30日

davidcheung

这个人很懒,什么都没留下

打赏 点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

搜索
欢迎关注我的个人公众号
最新 热点 随机
最新 热点 随机
DEEPFILTERNET:一种基于深度滤波的全频带音频低复杂度语音增强框架 奥地利匈牙利九日游旅程 论文阅读之Study of the General Kalman Filter for Echo Cancellation 小奥看房之鸿荣源珈誉府 杭州往返旅途及西溪喜来登和万怡的体验报告 2022年的第一篇碎碎念
奥地利匈牙利九日游旅程论文阅读之Study of the General Kalman Filter for Echo CancellationDEEPFILTERNET:一种基于深度滤波的全频带音频低复杂度语音增强框架
计算机组成原理笔记第六章(6.3~6.5) 《鸟哥的Linux私房菜》(基础篇)笔记整理(第6章)Part.2 S.V Beijing Travel 11&12:Capital Museum & film museum 2017 CSL 14th: Shandong Luneng Taishan F.C VS Guizhou Hengfeng Zhicheng F.C 好友动态 全运会本人观赛日程(更新完毕)
标签聚合
linux 生活 学习 python学习 鸟哥的linux私房菜 高中 Java leetcode Python 算法
最近评论
davidcheung 发布于 5 个月前(02月09日) The problem has been fixed. May I ask if you can s...
tk88 发布于 5 个月前(02月07日) Hmm is anyone else having problems with the pictur...
cuicui 发布于 9 个月前(10月20日) :wink:
niming 发布于 10 个月前(09月19日) 同级校友,能刷到太巧了
davidcheung 发布于 2 年前(08月16日) 我得找一下我之前整理的word文档看一下,如果找到了我就更新一下这篇文章。
Nolan 发布于 2 年前(07月25日) 您的笔记非常有帮助。贴图不显示了,可以更新一下吗?
davidcheung 发布于 3 年前(06月19日) 到没有看webrtc的代码。现在主要在看我们公司的代码了。。。只是偶尔看一看webrtc的东西。。。
aobai 发布于 3 年前(03月13日) gain_change_hangover_ 应该是每三个block 只能够调整一次,这样保证每帧...
匿名 发布于 5 年前(12月30日) 烫
小奥 发布于 5 年前(12月12日) webRTC里面的NS本身我记得就是在C++里面呀

COPYRIGHT © 2025 小奥的学习笔记. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

陕ICP备19003234号-1

鲁公网安备37120202000100号