当多个线程涉及到共享数据的时候,就会设计到线程安全的问题。非线程安全其实会在多个线程对同一个对象中的实例变量进行并发访问时发生,产生的后果就是“脏读”。发生脏读,就是取到的数据已经被其他的线程改过了。什么是线程安全呢?用并发编程实战里面的一段话解释说:

  当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要额
外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的

这里需要注意的是多个线程,如果一个线程肯定是线程安全的,而且这里的共享数据是指成员变量,不是局部变量,局部变量是

方法私有的,而方法运行时,对应的虚拟机方法栈是线程私有的,所以局部变量一定是方法安全的。

为了保证线程的安全,就要用到同步了。同步可以这么理解,只有等一个线程执行完这么一段需要同步的代码,其他的线程才能执行。而异步就是这段代码代码可以交替执行。

1.synchronized同步方法

synchronized同步方法的用法是

synchronized  修饰符  返回值 方法名(){

}

1.synchronized取得的锁都是对象锁,而不是把一段代码或函数当做锁

synchronized方法相当于给这个方法上了一把锁,锁就是拥有这个方法的实例对象,当多个线程访问一个类的同一个实例对象时,这个锁也就是这个实例对象,先获得这把锁的线程就可以执行同步方法里面的内容,其他线程只有等第一个线程执行结束自动释放锁或者程序抛出异常或者使用wait()等方法释放锁的情况下才能获得锁。

当多个线程访问一个类的多个实例对象时,jvm就创建了多把锁,多个线程获取到的锁不一样。这时候同步方法还是异步执行的。

2.synchronized方法锁重入

锁重入的意思是,一个线程已经拥有了这个对象的锁,再次请求该对象锁时,还是会保证成功,也就是说,在synchronized方法里面,再调用本类中的其他的synchronized方法,是永远可以得到锁的。否则,会造成死锁。

3.出现异常锁会自动释放

4.同步不具有继承性

也就是说父类中方法是同步的,子类继承父类的方法,这个方法就不是同步的了,需要再加上synchroized变成同步方法

5.如果多个线程持有一把锁,也就是只有一个实例对象,那么该对象里面的所有synchroized方法都具有同步性,也就是,当一个线程调用其中一个sycnhroized方法时,其他线程调用这个对象里面的其他synchroized也会处于阻塞状态。

使用synchroized方法有什么弊端呢?从运行时间来看,当一个线程取得锁以后,其他线程只有等待它释放锁以后才能执行方法里面的代码,从运行时间来看,这样会浪费很长的时间,怎么改变呢?就要用到同步语句块。

2.同步代码块

同步代码块如何解决上面问题呢?那就是只将需要同步的方法用

synchroized(this|任意对象|class){
}

括起来。括号里面的内容是一个监视器

只有代码块里面的代码是同步的,其余的代码还是异步的。

一、

1.当括号里面用this时,锁定的也是当前对象。

这时候其实和使用synchroized方法一样。

2.当括号里面是任意对象时。

当多个线程持有的对象监视器为同一个的前提下,如上。

但是当多个线程持有对象监视器为多个时,由于对象监视器不同,所以运行结果就是异步的。同步代码块放在非同步synchronized方法中进行生命,并不能保证调用方法的线程的执行同步/顺序性,也就是线程调用方法的顺序是无需的,虽然在同步块中执行的顺序是同步的,这样极其容易出现脏读。

所以最好保证对象监视器是同一个对象。锁非this对象具有的优点是:如果在一个类中由很多个synvhronized方法,这时虽然能实现同步,但是会阻塞,所以影响效率;如果使用同步代码块锁非this对象,则同步代码块中的程序与同步方法时异步的,不予其他锁this同步方法争抢this锁,大大提高运行效率。

3.括号里面是类时,静态同步方法一样。

静态同步方法其实是给类上锁,和普通的同步方法持有的不是一个锁。一个是类锁,一个是对象锁。

同步synchroized(Class)作用也是如此,但是对这个类的任何实例都起作用。

二、synchroized(任意对象)的三个结论

1.多个线程同时执行时呈同步效果

2.当其他线程执行任意对象中synchronized同步方法时呈同步效果

3.当其他线程执行任意对象里面的synchronized(this)代码块时呈同步效果

三、String的常量池特性

Jvm中有String常量池缓存的功能。

如果使用synchronized(string )时需要注意。“AA”与“AA”是相同的,也是如果两个同步块都使用AA,这两个代码块的锁时一样的。

四、snchroized方法无线等待与解决。

这里就是如果在snchroized方法中设置一个死循环,其他synchronized方法将无法获得执行机会。

而使用snchroized(任意对象)就可以解决这个问题

五、死锁

死锁怎么理解呢?大概就是“你先给我我就给你”“不,你给我我才给你”,两个人都不想让,就造成了这种死循环。

线程中的死锁通俗点讲就是互相等待对方先释放锁。不是只有一个锁里面嵌套着另外一个锁才会出现死锁

六、锁对象的改变。

当锁在运行中改变时,只要对象不变,即使对象的属性改变,那么锁还是没有改变。

三、volatile关键字

1.volatile关键字与死循环

想一想,如果你设置了一个boolean类型的变量,并在方法中设置一个while循环,循环的条件是这个boolean变量,如果运行中改变了这个变量的值,while会停下来么?答案是不会。

如果改由线程的方式呢?

但是在-server服务器模式中还是会死循环。什么原因呢?因为boolean变量的值存在于主内存及线程的工作内存中。在jvm被设置为-server模式时为了线程运行的效率,线程一直在工作内存中取值。改变boolean值得操作虽然被执行,更新的是主内存中的变量值,所以一直就是死循环的状态

这时候就可以用到volidate。

2.volidate非原子性

volidate只是强迫线程每一次取值的时候都从主内存中取,只具备可见性,并不具备同步性,那么也就不具备原子性。

3.原子操作

原子操作是不可分割的整体,没有其他线程能够中断或者检查正在原子操作中的变量。一个原子类型就是一个原子操作可用的对象。

下面是原子类。

 AtomicBoolean -- 原子布尔
AtomicInteger -- 原子整型
AtomicIntegerArray -- 原子整型数组
AtomicLong -- 原子长整型
AtomicLongArray -- 原子长整型数组
AtomicReference -- 原子引用
AtomicReferenceArray -- 原子引用数组
AtomicMarkableReference -- 原子标记引用
AtomicStampedReference -- 原子戳记引用
AtomicIntegerFieldUpdater -- 用来包裹对整形 volatile 域的原子操作
AtomicLongFieldUpdater -- 用来包裹对长整型 volatile 域的原子操作
AtomicReferenceFieldUpdater -- 用来包裹对对象 volatile 域的原子操作

4.原子类也并不完全安全

当原子类在具有逻辑性的操作下也会具有随机性。

因为原子类的方法虽然是原子的,但是方法与方法之间却不是原子的。解决的方法就是必须使用同步

4.synchronized代码块由volidate同步的功能

关键字synchronized保证在同一时刻,只有一个线程可以执行某一个方法或某一个代码块。包含两个特征:互斥性和可见性。

同步方法、同步代码块、volidate变量的使用的更多相关文章

  1. Java 基础 线程的Runnable接口 /线程的同步方法 /同步代码块

    笔记: /**通过 Runnable接口来实现多线程 * 1. 创建一个实现runnable 接口的类 * 2. 在类中实现接口的run() 抽象方法 * 3. 创建一个runnable 接口实现类的 ...

  2. 对象及变量的并发访问(同步方法、同步代码块、对class进行加锁、线程死锁)&内部类的基本用法

    主要学习多线程的并发访问,也就是使得线程安全. 同步的单词为synchronized,异步的单词为asynchronized 同步主要就是通过锁的方式实现,一种就是隐式锁,另一种是显示锁Lock,本节 ...

  3. 线程同步 synchronized 同步代码块 同步方法 同步锁

    一 同步代码块 1.为了解决并发操作可能造成的异常,java的多线程支持引入了同步监视器来解决这个问题,使用同步监视器的通用方法就是同步代码块.其语法如下: synchronized(obj){ // ...

  4. 深入理解使用synchronized同步方法和同步代码块的区别

    一.代码块和方法之间的区别 首先需要知道代码块和方法有什么区别: 构造器和方法块,构造器可以重载也就是说明在创建对象时可以按照不同的构造器来创建,那么构造器是属于对象,而代码块呢他是给所有的对象初始化 ...

  5. java中的synchronized同步代码块和同步方法的区别

    下面这两段代码有什么区别? //下列两个方法有什么区别 public synchronized void method1(){} public void method2(){ synchronized ...

  6. 牛客网Java刷题知识点之同步方法和同步代码块的区别(用synchronized关键字修饰)

    不多说,直接上干货! 扩展博客 牛客网Java刷题知识点之多线程同步的实现方法有哪些 为何要使用同步?      java允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时(如数据的增删改查 ...

  7. 线程的同步机制:同步代码块&同步方法

    解决存在的线程安全问题:打印车票时出现重票,错票 使用同步代码块的解决方案 TestWindow2 package com.aff.thread; /* 使用实现Runnable接口的方式,售票 存在 ...

  8. 0037 Java学习笔记-多线程-同步代码块、同步方法、同步锁

    什么是同步 在上一篇0036 Java学习笔记-多线程-创建线程的三种方式示例代码中,实现Runnable创建多条线程,输出中的结果中会有错误,比如一张票卖了两次,有的票没卖的情况,因为线程对象被多条 ...

  9. Android(java)学习笔记68:同步代码块 和 同步方法 的应用

    1. 同步代码块 和 同步方法 代码示例: (1)目标类,如下: package cn.himi.text; public class SellTicket implements Runnable { ...

随机推荐

  1. 饮冰三年-人工智能-linux-02 初始Linux

    参考博客:https://www.cnblogs.com/linhaifeng/articles/6045600.html 1:初始Linux命令 右击,开启终端,或者ctrl+alt[F1-F6]的 ...

  2. Deap thinking

    它使任何人离任何问题的答案间的距离变得只有点击一下鼠标这么远! ---------<美国周刊> ---------周志华<机器学习>   所以我们更应该学会Deep Think ...

  3. MyBatis - 7.MyBatis逆向 Generator

    MyBatis Generator: 简称MBG,是一个专门为MyBatis框架使用者定制的代码生成器,可以快速的根据表生成对应的映射文件,接口,以及bean类.支持基本的增删改查,以及QBC风格的条 ...

  4. [BZOJ3011][Usaco2012 Dec]Running Away From the Barn

    题意 给出一棵以1为根节点树,求每个节点的子树中到该节点距离<=l的节点的个数 题解 方法1:倍增+差分数组 首先可以很容易的转化问题,考虑每个节点对哪些节点有贡献 即每次对于一个节点,找到其第 ...

  5. WPF中datagrid不显示滚动条问题

    WPF中DataGrid是自带滚动条的,当内容显示不下时可以使用滚动条显示.但是,开发中遇到了DataGrid一直不显示滚动条.之前也曾遇到过同类问题,再次经过查找,发现是StackPanel的原因, ...

  6. Python_自定义模块

    自定义模块例子(web简单框架): 专门处理逻辑的包:处理各种访问需求 数据库的交互:面临各种的查询,删改 ,dba, 配置文件(全局配置文件):列存储数据的地方,HTML代码存储地方 实现: 代码: ...

  7. windows云服务器数据迁移

    刚入职,第一个任务是完成windows腾讯云到windows华为云上的MySQL数据库迁移.之前都是在CentOS上搞,感觉没啥难度,一口答应,没想到各种坑接踵而来.次数不再叙述坑都有哪些了,说说怎么 ...

  8. python3改版后的特征

    1.原始数据类型和运算符 # 整数 3 # => 3 # 算术没有什么出乎意料的 1 + 1 # => 2 8 - 1 # => 7 10 * 2 # => 20 # 但是除法 ...

  9. Codeforces 609F Frogs and mosquitoes 线段树

    Frogs and mosquitoes 用线段树维护每个点覆盖的最小id, 用multiset维护没有吃的蚊子. #include<bits/stdc++.h> #define LL l ...

  10. jenkins使用教程之系统设置

    如果jenkins环境还没有搭建好的话可以看这篇文章点击查看 进入jenkins首页,点击系统管理 点击系统设置,进入系统设置界面 1.主目录,点击高级 主目录是存放Jenkins所有的文件的,工作空 ...