synchronized是Java中的关键字,是一种常用的线程同步锁。

用法

注意:在理解synchronized时,要知道一个核心点,synchronized锁定的不是代码,而是对象。使用synchronized时,其会申请对象的堆内存,进行锁定。

写法一

    Object o = new Object(); // 锁对象
public void test01(){
//任何线程要执行以下的代码,必须先拿到锁
synchronized (o){
// doSomething...
}
}

写法二

上述写法是创建一个锁对象,其实可以自身作为锁对象。

    public void test02(){
synchronized (this){
// doSomething...
}
}

写法三

同写法二。

    public synchronized void test03(){
// doSomething...
}

写法四

锁定静态方法。静态方法是属于类方法,没有对象。

    public synchronized static void test04(){
}

写法五

同写法四

    public static void test04(){
synchronized (SynchronizeTest.class){
}
}

测试线程安全问题

演示代码:

public class TestSynch implements Runnable{
private int count = 10;
@Override
public /*synchronized*/ void run() {
count--;
System.out.println(Thread.currentThread().getName()+"count="+count);
}
public static void main(String[] args) {
TestSynch t = new TestSynch();
for (int i = 0; i < 8; i++) {
new Thread(t,"结果是"+i).start();
}
}
}

结果是:

加入synchronized:

注意事项

  1. 加锁方法和不加锁方法

    public class Account {
    int count = 100; // 写入数据
    public synchronized void set(int s){
    try {
    Thread.sleep(1000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    this.count = s;
    } // 读取数据
    public /*synchronized*/ void get(){
    System.out.println(count);
    }
    public static void main(String[] args) {
    Account a = new Account();
    new Thread(()->a.set(1)).start();
    a.get();
    try {
    Thread.sleep(500);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    a.get();
    }
    }

    在实际业务场景中,往往将读方法不加锁,写的方法加锁,这样会导致一个问题,也就是读的数据是写之前的数据,导致脏读问题。

解决方案就是,在读方法上也加锁。

  1. 加锁方法不影响不加锁方法的执行;

  2. 加锁方法访问另外一个加锁方法,一个线程拥有某个对象的锁,再次申请的时候可以再次得到这把锁(相当于锁上了两把同样的锁);子类的同步方法调用父类的同步方法也可以;

  3. synchronized 遇到异常,锁会被释放。如果不想该锁被释放,就直接catch;

  4. 不要以字符创常量作为锁对象。

    public class StringAsSynchObject {
    private String stra = "hello";
    private String strb = "hello";
    void test1(){
    synchronized (stra){
    }
    }
    void test2(){
    synchronized (strb){
    }
    }
    }

    在上述代码中,因为stra和strb 锁的是同一个对象,如果用到了同一个类库,在该类库中的代码锁定了字符串"hello",我们读不到源码,而在业务代码中也锁定了同样的字符串,这就有可能会造成非常诡异的死锁阻塞。因为程序和类库不经意用了同一把锁。(这种情况一般没办法调试)。所以通常不要字符串作为锁定对象。

  5. synchronize 锁定的粒度越小(即锁定的业务代码越少),效率越高。

  6. synchronize 锁释放的情况:

    1)线程执行完毕;

    2)线程发生异常;

    3)线程进入休眠状态。

  7. synchronize 是互斥锁,可重入锁。

  8. wait()和notify()/notifyAll() 与 synchronize同时出现。

作者:追梦1819
原文:https://www.cnblogs.com/yanfei1819/p/10694661.html
版权声明:本文为博主原创文章,转载请附上博文链接!

并发编程之synchronize的更多相关文章

  1. [转载]并发编程之Operation Queue和GCD

    并发编程之Operation Queue http://www.cocoachina.com/applenews/devnews/2013/1210/7506.html 随着移动设备的更新换代,移动设 ...

  2. Java并发编程之CAS

    CAS(Compare and swap)比较和替换是设计并发算法时用到的一种技术.简单来说,比较和替换是使用一个期望值和一个变量的当前值进行比较,如果当前变量的值与我们期望的值相等,就使用一个新值替 ...

  3. 并发编程之wait()、notify()

    前面的并发编程之volatile中我们用程序模拟了一个场景:在main方法中开启两个线程,其中一个线程t1往list里循环添加元素,另一个线程t2监听list中的size,当size等于5时,t2线程 ...

  4. 并发编程之 Exchanger 源码分析

    前言 JUC 包中除了 CountDownLatch, CyclicBarrier, Semaphore, 还有一个重要的工具,只不过相对而言使用的不多,什么呢? Exchange -- 交换器.用于 ...

  5. 并发编程之 Condition 源码分析

    前言 Condition 是 Lock 的伴侣,至于如何使用,我们之前也写了一些文章来说,例如 使用 ReentrantLock 和 Condition 实现一个阻塞队列,并发编程之 Java 三把锁 ...

  6. python并发编程之Queue线程、进程、协程通信(五)

    单线程.多线程之间.进程之间.协程之间很多时候需要协同完成工作,这个时候它们需要进行通讯.或者说为了解耦,普遍采用Queue,生产消费模式. 系列文章 python并发编程之threading线程(一 ...

  7. python并发编程之gevent协程(四)

    协程的含义就不再提,在py2和py3的早期版本中,python协程的主流实现方法是使用gevent模块.由于协程对于操作系统是无感知的,所以其切换需要程序员自己去完成. 系列文章 python并发编程 ...

  8. python并发编程之asyncio协程(三)

    协程实现了在单线程下的并发,每个协程共享线程的几乎所有的资源,除了协程自己私有的上下文栈:协程的切换属于程序级别的切换,对于操作系统来说是无感知的,因此切换速度更快.开销更小.效率更高,在有多IO操作 ...

  9. python并发编程之multiprocessing进程(二)

    python的multiprocessing模块是用来创建多进程的,下面对multiprocessing总结一下使用记录. 系列文章 python并发编程之threading线程(一) python并 ...

随机推荐

  1. eclipse配置tomcat 8.0.24服务器

    开发j2ee,肯定需要web容器来运行web项目,目前web容器有tomcat,jetty,Jboss,weblogic等服务器,最为常用的是tomcat服务器,其与eclipse的配置如下: tom ...

  2. 买了个vultr的vps,准备把博客转过去,顺便记录一点操作。

    1.shadow影子socks梯子已经搭好了,步骤: apt-get install python-pip pip install shadowsocks 任意目录创建配置文件json(ss可以在很多 ...

  3. sudo -s/sodo -i/su root

    sudo : 暂时切换到超级用户模式以执行超级用户权限,提示输入密码时该密码为当前用户的密码,而不是超级账户的密码.不过有时间限制,Ubuntu默认为一次时长15分钟.su : 切换到某某用户模式,提 ...

  4. hadoop1.2.1+hbase0.94.11+nutch2.2.1+elasticsearch0.90.5安装配置攻略

    一.背景 最近由于项目和论文的需要,需要搭建一个垂直搜索的环境,查阅了很多资料,决定使用Apache的一套解决方案hadoop+hbase+nutch+es.这几样神器的作用就不多作介绍了,自行参考各 ...

  5. Android应用-底部导航栏的使用

    目录 1. 设计底部导航栏页面 1.1. 创建必须的文件夹 1.2. 设计主页面 2. 设计逻辑函数 3. 项目展示 底部导航栏是基于Bottom Navigation Bar 插件使用的 这个插件包 ...

  6. leetcode 23. 合并K个排序链表 JAVA

    题目: 合并 k 个排序链表,返回合并后的排序链表.请分析和描述算法的复杂度. 示例: 输入: [   1->4->5,   1->3->4,   2->6 ] 输出: ...

  7. 四、Centos linux系统优化

    1.     无论是哪个版本的linux,都会提供32位和64位的两个版本的镜像. i386为32位 x86_64为64位 两者的区别: 1)目标:需要大量的内存需求的行业为64位,普通用户的需求为3 ...

  8. Logstash 性能及其替代方案

    介绍 当谈及集中日志到 Elasticsearch 时,首先想到的日志传输(log shipper)就是 Logstash.开发者听说过它,但是不太清楚它具体是干什么事情的: 当深入这个话题时,我们才 ...

  9. C# Winform下一个热插拔的MIS/MRP/ERP框架15(窗体基类场景1)

    最基础的窗体基类其实是通过应用场景反推的结构. 以下是场景一: 单表应用,普通的数据,比如单位/颜色/特殊字典等使用者少的,无需过多控制的可以使用一个数据表格来管理. 和Excel表格差不多,批量修改 ...

  10. [转贴]VC编译器版本号_MSC_VER and _MSC_FULL_VER

    Visual Studio version and discrimination macros Abbreviation Product name [Visual Studio version] †1 ...