java多线程编程核心技术 2

雷薄
• 阅读 1780
  1. “非线程安全”其实会在多个线程对同一个对象中的实例变量进行并发访问时发生,产生的后果就是“脏读”,也就是取到的数据其实是被更改过的。而“线程安全”就是以获得的实例变量的值是经过同步处理的,不会出现脏读的现象。
  2. “非线程安全”问题存在于“实例变量”中,如果是方法内部的私有变量,则不存在“非线程安全”问题,所得结果也就是“线程安全”的了。
  3. 在两个线程访问同一个对象中的同步方法时一定是线程安全的。
  4. 关键字synchronized取得的锁都是对象锁,而不是一段代码或方法当作锁,哪个线程先执行带synchronized关键字的方法,哪个 线程就是持有该方法所属对象的锁Lock,那么其他线程只能呈等待状态,前提是多个线程访问的是同一个对象。但多个线程访问多个对象,则JVM会创建多个锁。
  5. 调用关键字synchronized声明的方法一定是排队运行的,只有共享资源的读写才需要同步化。
  6. A线程先持有object对象的Lock锁,B线程可以以异步的方式调用object对象中的非synchronized类型的方法
    A线程先持有object对象的Lock锁,B线程如果在这时调用object对象中的synchronize类型的方法则需等待,也就是同步。
  7. 发送脏读的情况是在读取实例变量时,此值已经被其他线程更改过了。
  8. 关键字synchronized拥有锁重入的功能,也就是在使用synchronized时,当一个线程得到一个对象锁后,再次请求此对象时是可以再次得到该对象的锁的。这也证明在一个synchroized方法内部调用本类的其他synchronized方法时,是永远可以得到锁的。
  9. 当存在父子类继承关系时,子类是完全可以通过“可重入锁”调用父类的同步方法的。
  10. 出现异常的锁被自动释放。
  11. 同步不能继承,所以还得在子类的方法中添加synchronized关键字。
  12. synchronized方法是对当前对象进行加锁,而synchronized代码块是对某一个对象进行加锁。
  13. 当两个并发线程访问同一个对象object中的synchronized(this)同步代码块时,一段时间内只能有一个线程被执行,另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
  14. 不在synchronized块中就是异步执行,在synchronized块中就是同步执行。
  15. 当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对同一个object钟所有其他synchronized(this)同步代码块的访问被阻塞,这说明synchronized使用的“对象监视器”是一个。
  16. 和synchronized方法一样,synchronized(this)代码块也是锁定当前对象的。
  17. 锁非this对象具有一定的优点:如果在一个类中有很多个synchronized方法,这时虽然能实现同步,但会受到阻塞,所以影响运行效率;但如果使用同步代码块锁非this对象,则synchronized(非this)代码块中的程序与同步方法是异步的,不与其他锁this同步方法争抢this锁,则可以大大提高运行效率。
  18. 多个线程调用同一个对象中的不同名称的synchronized同步方法或synchronized(this)同步代码块时,调用的效果就是按顺序执行,也就是同步的,阻塞的。
  19. 同步代码块放在非同步synchronized方法中进行声明,并不能保证调用方法的线程的执行同步/顺序性,也就是线程调用方法是顺序是无序的,虽然在同步代码块中执行的顺序是同步的,这样极易出现“脏读”问题。
  20. synchronized(非this对象x)格式的写法是将x对象本身作为“对象监视器”,这样就可以得出以下3个结果:

1)当多个线程同时执行synchronized(x){}同步代码块呈同步效果。
2)当其他线程执行x对象中synchronized同步方法时呈同步效果。
3)当其他线程执行x对象方法里面的synchroinzed(this)代码块时也呈同步效果。
但要注意,如果其他线程调用不加synchronized关键字的方法时,还是异步调用。

  1. synchronized关键字加到static静态方法上是给Class类上锁,而synchroinzed关键字加到非static静态方法上是给对象上锁。
  2. 异步的原因是持有不同的锁,一个是对象锁,另外一个是Class锁,而Class锁可以对类的所有对象实例起作用。
  3. 当string的多个值都是相同时候(aa),两个线程持有相同的锁,所以造成线程B不能执行。这就是String 常量池所带来的问题。因此大多数的情况下,同步synchronized代码块都不使用string作为锁对象,而改用其他,比如new object()实例化一个Object对象,但它并不放入缓存中.
  4. 因为同步的线程都在等待根本不可能被释放的锁,从而导致所有的任务都无法继续完成,是线程死锁。
  5. 进入jdk的bin目录,执行jps命令,获取线程run的id,再执行jstack -l run线程id。
  6. 在内置类中有两个同步方法,但使用的却是不同的锁,打印的结果也是异步的。
  7. 同步代码块synchronized(class2)对class2上锁以后,其他线程只能以同步的方式调用class2中的静态同步方法。
  8. 如果同时持有相同的锁对象,则这些线程之间就是同步的;如果分别获得锁对象,这些线程之间就是异步的。
  9. 只要对象不变,即使对象的属性被改变,运行的结果还是同步的。
  10. 关键字volatile的主要作用是变量在多个线程间可见。
  11. 关键字volatile的作用是强制从公共堆栈中取得变量的值,而不是从线程私有数据栈中取得变量的值。
  12. volatile关键字最致命的缺点是不支持原子性。
  13. 关键字volatile主要使用的场合是多个线程中可以感知实例变量被更改了,并且可以获得最新的值使用,也就是用多线程读取共享变量可以获得最新值使用。
  14. read和load阶段:从主存复制变量到当前线程工作内存;

    use和assign阶段:执行代码,改变共享变量值;
    store和write阶段:用工作内存数据刷新主内存对应变量的值;
    
  15. 对于用volatile修饰的变量,jvm虚拟机只是保证从主内存加载线程工作内存的值是最新的。
  16. 原子操作是不能分割的整体,没有其他线程能够中断或检查正常原子操作中的变量。
  17. atomicInteger也不一定是安全的,虽然addAndGet()方法是原子的,但方法和方法之间的调用却不是原子的。解决这样的问题必须要用同步。

点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
4年前
java锁学习(一)
作用能够保证同一时刻,最多只有一个线程执行该段代码,以达到并发安全的效果主要用于同时刻对线程间对任务进行锁地位synchronized是JAVA的原生关键字,是JAVA中最基本的互斥手段,是并发编程中的元老角色不使用并发的后果不使用并发会导致多线程情况下,同一个数据被多个线程同时更改,造成结果和预期不一致
Wesley13 Wesley13
4年前
String、StringBuffer、StringBuilder的区别
String字符串常量StringBuffer字符串变量(线程安全)StringBuilder字符串变量(非线程安全) 简要的说,String类型和StringBuffer类型的主要性能区别其实在于String是不可变的对象,因此在每次对String类型进行改变的时候其实都等同于生成了一个新的String
Wesley13 Wesley13
4年前
java ThreadLocal
ThreadLocal是什么定义:提供线程局部变量;一个线程局部变量在多个线程中,分别有独立的值(副本)特点:简单(开箱即用)、快速(无额外开销)、安全(线程安全)场景:多线程场景(资源持有、线程一致性、并发计算、线程安全等场景)ThreadLocal基本API 构
Wesley13 Wesley13
4年前
java多线程(四)之同步机制
1.同步的前提  多个线程  多个线程使用的是同一个锁2.同步的好处  同步的出现解决了多线程的安全问题3.同步的弊端  当线程较多时,因为每个线程都会去判断同步上的锁,这样是很耗费资源的,会降低程序的运行效率.4.同步方法:  1.就是将同步关键字,synchronized加到方法上,此时的锁对象是this  
Stella981 Stella981
4年前
C# 多线程之List的线程安全问题
网上关于List的线程安全问题将的很少,所以自己实验了一把,发现确实是线程不安全的.所以当你在进行多线程编程中使用了共享的List集合,必须对其进行线程安全处理.List的Add方法是线程不安全的,List的源码中的Add方法,使用了每次当当前的元素达到上限,通过创建一个新的数组实例,并给长度翻倍的操作.如果单线程操作不会有问题,直接扩容,然后继续往里面
Wesley13 Wesley13
4年前
Java 并发数据结构
\TOCM\因为Java提供了一些非线程安全的数据结构如HashMap,ArrayList,HashSet等。所有在多线程环境中需要使用支持并发访问操作的数据结构。并发ListVector,CopyOnWriteArrayList是线程安全的List。ArrayList是线程不安全的。如果一定要使用,需要:Collection
Wesley13 Wesley13
4年前
Java ThreadLocal的内存泄漏问题
ThreadLocal提供了线程独有的局部变量,可以在整个线程存活的过程中随时取用,极大地方便了一些逻辑的实现。常见的ThreadLocal用法有:\存储单个线程上下文信息。比如存储id等;\使变量线程安全。变量既然成为了每个线程内部的局部变量,自然就不会存在并发问题了;\减少参数传递。比如做一个trace工具,能够输出工程从开始到结
Wesley13 Wesley13
4年前
Java中的锁原理、锁优化、CAS、AQS,看这篇就对了!
01为什么要用锁?锁是为了解决并发操作引起的脏读、数据不一致的问题。02 锁实现的基本原理2.1、volatileJava编程语言允许线程访问共享变量,为了确保共享变量能被准确和一致地更新,线程应该确保通过排他锁单独获得这个变量。Java语言提供了volatile,在某些
Easter79 Easter79
4年前
ThreadLocal详解
ThreadLocal翻译成中文比较准确的叫法应该是:线程局部变量。  这个玩意有什么用处,或者说为什么要有这么一个东东?先解释一下,在并发编程的时候,成员变量如果不做任何处理其实是线程不安全的,各个线程都在操作同一个变量,显然是不行的,并且我们也知道volatile这个关键字也是不能保证线程安全的。那么在有一种情况之下,我们需要满足这样一个条件:变量是
Wesley13 Wesley13
4年前
Java分布式锁看这篇就够了
\什么是锁?在单进程的系统中,当存在多个线程可以同时改变某个变量(可变共享变量)时,就需要对变量或代码块做同步,使其在修改这种变量时能够线性执行消除并发修改变量。而同步的本质是通过锁来实现的。为了实现多个线程在一个时刻同一个代码块只能有一个线程可执行,那么需要在某个地方做个标记,这个标记必须每个线程都能看到
待兔 待兔
1年前
Java内存的可见性
Java内存的可见性可见性:一个线程对共享变量的修改,能够及时被其它线程看到共享变量:如果一个变量在多个线程的工作内存中都存在副本,那么这个变量就是这几个线程的共享变量Java内存模型(JMM):描述了Java程序中各种线程共享变量的访问规则,以及在JVM