1、线程同步概述

线程之间有可能共享一些资源,比如内存、文件、数据库等。多个线程同时读写同一份共享资源时,就可能引起冲突,所以引入了线程的“同步”机制。

所谓同步,就是说线程要有先来后到,排队执行操作,而不是同时进行操作。目的就是为了防止多个线程在访问相同数据对象时,对数据造成污染和破坏。

为了实现同步,Java中提供了“锁”的机制,可以给共享资源加上一把锁,这把锁只有一把钥匙,哪个线程获取了这把钥匙,才有权利去访问该共享资源。而实现“锁”机制的关键字,就是 synchronized

2、synchronized

synchronized 的使用很简单
  • 同步方法:   访问权限修饰符  synchronized 数据返回类型 方法名() { ... }
  • 同步语句块:synchronized (共享对象名) { ... }
  • 不能修饰构造函数、抽象方法、成员变量

下面我们来看个简单的demo:
//Data 共享数据
public class Data { private static int count = 0; public static int getCount() {
return count;
} public static void add() {
count++;
} } //Counter 操作共享数据
public class Counter { public synchronized void count() {
Data.add();
System.out.println("current count = " + Data.getCount());
} } //MyThread
public class MyThread extends Thread { private Counter counter; public MyThread(Counter counter) {
this.counter = counter;
} @Override
public void run() {
for(int i = 0; i < 50; i++) {
counter.count();
}
} } //Test
public class Test {
public static void main(String[] args) {
Counter counter1 = new Counter();
Counter counter2 = new Counter(); Thread t1 = new MyThread(counter1);
Thread t2 = new MyThread(counter2);
t1.start();
t2.start();
}
} //输出结果示例
...
current count = 2
current count = 2
current count = 3
current count = 4
current count = 5
current count = 6
current count = 7
...
x
 
1
//Data 共享数据
2
public class Data {
3

4
    private static int count = 0;
5

6
    public static int getCount() {
7
        return count;
8
    }
9

10
    public static void add() {
11
        count++;
12
    }
13

14
}
15

16
//Counter 操作共享数据
17
public class Counter {
18

19
    public synchronized void count() {
20
        Data.add();
21
        System.out.println("current count = " + Data.getCount());
22
    }
23

24
}
25

26
//MyThread
27
public class MyThread extends Thread {
28

29
    private Counter counter;
30

31
    public MyThread(Counter counter) {
32
        this.counter = counter;
33
    }
34

35
    @Override
36
    public void run() {
37
        for(int i = 0; i < 50; i++) {
38
            counter.count();
39
        }
40
    }
41

42
}
43

44

45
//Test
46
public class Test {
47
    public static void main(String[] args) {
48
        Counter counter1 = new Counter();
49
        Counter counter2 = new Counter();
50

51
        Thread t1 = new MyThread(counter1);
52
        Thread t2 = new MyThread(counter2);
53
        t1.start();
54
        t2.start();
55
    }
56
}
57

58
//输出结果示例
59
...
60
current count = 2
61
current count = 2
62
current count = 3
63
current count = 4
64
current count = 5
65
current count = 6
66
current count = 7
67
...

如上例中,可以看到在 Counter 类的 count() 方法我们已经加上了 synchronized 关键字,该方法会将共享数据 Data.count 自增,然后进行打印输出。但是,我们发现输出的结果显示,count 竟然有重复,这意味着数据出现了脏读,我们在打印前,有其他线程对共享数据再次进行了修改!锁机制无效,为什么?

因为 synchronized 取得的锁是对象锁,而不是把一段代码或方法当成锁。这意味着,要实现同步,即某线程执行,其他线程等待,前提是多个线程访问的是同一个对象。而上例中,显然 counter1 和 counter2 是两个对象,我们的锁也就没有效果。

我们试着把两个线程的 Counter 类统一下,锁机制就如我们所愿了:
//Test
public class Test {
public static void main(String[] args) {
Counter counter = new Counter();
Thread t1 = new MyThread(counter);
Thread t2 = new MyThread(counter);
t1.start();
t2.start();
}
} //输出结果示例
current count = 1
current count = 2
current count = 3
current count = 4
current count = 5
current count = 6
current count = 7
current count = 8
...
1
10
 
1
//Test
2
public class Test {
3
    public static void main(String[] args) {
4
        Counter counter = new Counter();
5
        Thread t1 = new MyThread(counter);
6
        Thread t2 = new MyThread(counter);
7
        t1.start();
8
        t2.start();
9
    }
10
}
11

12
//输出结果示例
13
current count = 1
14
current count = 2
15
current count = 3
16
current count = 4
17
current count = 5
18
current count = 6
19
current count = 7
20
current count = 8
21
...

最后,简单总结:
  • 只对改变共享资源的地方进行同步,而不是所有方法。同步块越大,多线程的效率也越低
  • synchronized 关键字可以修饰方法和代码块,但是不能修饰构造函数、抽象方法、成员变量
  • synchronized 关键字无法继承
  • synchronized 不论在方法还是对象上,取得的锁都是对象,注意搞清楚锁定的是哪个对象


[03] 线程同步 synchronized的更多相关文章

  1. Java线程(二):线程同步synchronized和volatile

    上篇通过一个简单的例子说明了线程安全与不安全,在例子中不安全的情况下输出的结果恰好是逐个递增的(其实是巧合,多运行几次,会产生不同的输出结果),为什么会产生这样的结果呢,因为建立的Count对象是线程 ...

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

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

  3. 线程同步synchronized,wait,notifyAll 测试示例

    https://www.cnblogs.com/LipeiNet/p/6475851.html 一  synchronized synchronized中文解释是同步,那么什么是同步呢,解释就是程序中 ...

  4. 线程同步synchronized和ReentrantLock

    一.线程同步问题的产生及解决方案 问题的产生: Java允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时(如数据的增删改查),将会导致数据不准确,相互之间产生冲突. 如下例:假设有一个卖票 ...

  5. 多线程学习-基础( 九)线程同步Synchronized关键字

    一.线程同步1.synchronized关键字的作用域有二种:(1)某个对象实例内:synchronized aMethod(){}可以防止多个线程同时访问这个对象的synchronized方法(如果 ...

  6. Java线程同步synchronized的理解

    JVM中(留神:马上讲到的这两个存储区只在JVM内部与物理存储区无关)存在一个主内存(Main Memory),Java中所有的变量存储在主内存中,所有实例和实例的字段都在此区域,对于所有的线程是共享 ...

  7. java多线程:线程同步synchronized(不同步的问题、队列与锁),死锁的产生和解决

    0.不同步的问题 并发的线程不安全问题: 多个线程同时操作同一个对象,如果控制不好,就会产生问题,叫做线程不安全. 我们来看三个比较经典的案例来说明线程不安全的问题. 0.1 订票问题 例如前面说过的 ...

  8. Day13_71_线程同步(synchronized)

    线程同步 * 异步编程模型和同步编程模拟的区别? - 有T1和T2 两个线程 > 异步编程模型:T1线程执行T1的,T2线程执行T2的,谁也不等谁 > 同步编程模型:T1和T2 线程执行, ...

  9. C++并发编成 03 线程同步

    这一节主要讲讲线程同步的方式,C++ 11中提供了丰富的线程同步元语,如condition_variable,futrue,std::packaged_task<>,std::promis ...

随机推荐

  1. 华为P20无线投屏到电脑 绝地求生投射电脑

    如今出门在外,必不可少的就是手机,如果没有了手机,每个人都会感觉没有安全感,感觉和世界失去了联系,我们每天每个人都在使用手机,但是作为华为手机用户的你,了解华为P20无线投屏到电脑是怎么操作的吗? 使 ...

  2. Caused by: Java.lang.NoSuchMethodError: javax.persistence.JoinColumn.foreignKey()Ljavax/persistence/ForeignKey;

    Caused by: Java.lang.NoSuchMethodError: javax.persistence.JoinColumn.foreignKey()Ljavax/persistence/ ...

  3. 有效运维的 on-call 机制

    [编者按]本文作者为云告警平台OneAlert负责人,著<云计算与OpenStack>,在IT运营管理.云计算方面从业10多年. 正文 互联网技术的发展,离不开运维支撑工作,没有零bug的 ...

  4. Orchard详解--第二篇 启动

    Orchard Framework作为框架它与类库最大的区别就是框架是将一系列零散的组件组合在一起形成一个整体,接下来就对Orchard Framework如何分析Orchard如何将相关组件结合在一 ...

  5. sublime text 3 优化配置

    目录 1. sublime text 3 模板插件 SublimeTmpl 配置 修改模板内容格式 修改快捷键 2. 设置sublime text的 TAB 为4个空格 3. 添加markdown支持 ...

  6. myeclipse10 blue版激活码

    http://blog.itpub.net/27042095/viewspace-1164998/

  7. Visual Studio语言设置

    按照的是中文的visual studio,用起来很不方便,因为程序员的都是英文版,平时交流时也是英文的名字 转换语言时发现只有中文和跟随windows系统的设置 官方给的文档看的不是很清楚 查阅资料后 ...

  8. 洗礼灵魂,修炼python(91)-- 知识拾遗篇 —— pymysql模块之python操作mysql增删改查

    首先你得学会基本的mysql操作语句:mysql学习 其次,python要想操作mysql,靠python的内置模块是不行的,而如果通过os模块调用cmd命令虽然原理上是可以的,但是还是不太方便,那么 ...

  9. Vue2 学习笔记3

    文中例子代码请参考github 定义Vue组件 什么是组件: 组件的出现,就是为了拆分Vue实例的代码量的,能够让我们以不同的组件,来划分不同的功能模块,将来我们需要什么样的功能,就可以去调用对应的组 ...

  10. CentOS6.5内 MySQL5.7.19编译安装

    作为博主这样的Linux菜鸟,CentOS下最喜欢的就是yum安装.但有时候因为特殊情况(例如被墙等),某些软件可能没办法直接通过yum来安装,这时候我们可以使用编译安装或者直接二进制文件安装. 本博 ...