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. Deep Learning - 2 反向传播

    深度神经网络的学习基于两个关键技术: Stochastic Gradient Descent Backpropagation 利用 SGD 算法学习 Weights 和 Biases,利用 Backp ...

  2. Android 应用程序崩溃日志捕捉

    程序崩溃是应用迭代中不可避免的问题,即使有着5年或者10年经验的程序猿也无法完全保证自己的代码没有任何的bug导致崩溃,现在有一些第三方平台可以帮助我们搜集应用程序的崩溃,比如友盟,详情如下图 虽然能 ...

  3. spring Boot 出现:org.springframework.context.ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.

    org.springframework.context.ApplicationContextException: Unable to start ServletWebServerApplication ...

  4. 2019年Web前端入门的自学路线

    本文最初发表于博客园,并在GitHub上持续更新前端的系列文章.欢迎在GitHub上关注我,一起入门和进阶前端. 以下是正文.本文内容不定期更新. 我前几天写过一篇文章:<裸辞两个月,海投一个月 ...

  5. windows网络编程中文 笔记(二)

    IPv4 地址段 IPv4地址类别 种类 网络部分 第1个数字 端点数字 A  8位  0-127  16777216 B  16位  128-191  65526 C  24位  193-223   ...

  6. 洗礼灵魂,修炼python(71)--爬虫篇—【转载】xpath/lxml模块,爬虫精髓讲解

    Xpath,lxml模块用法 转载的原因和前面的一样,我写的没别人写的好,所以我也不浪费时间了,直接转载这位崔庆才大佬的 原帖链接:传送门 以下为转载内容: --------------------- ...

  7. Process 0:0:0 (0x1ffc) Worker 0x00000001E580A1A0 appears to be non-yielding on Scheduler 3. Thread creation time: 13153975602106.

    现场报错如下: Process 0:0:0 (0x1ffc) Worker 0x00000001E580A1A0 appears to be non-yielding on Scheduler 3. ...

  8. 6. svg学习笔记-路径

    路径相比于多边形<polygon>元素具有更强绘图能力,<polygon>元素可以绘制任意的多边形,而路径可以绘制任意的轮廓线,是线段,曲线,圆弧的组合形式.svg中可以使用& ...

  9. Jetbrains IntelliJ IDEA PyCharm 注册激活(2018最新)

    AppCode CLion DataGrip GoLand IntelliJ IDEA PhpStorm PyCharm Rider RubyMine WebStorm下载注册激活 官方下载地址 Ap ...

  10. linux ubuntu 关于vim得一些基本命令

    1.vim显示行号 :set number 2. 快捷键 J 向下 K 往上 H 向左 L 向右 ctrl+shift+T 打开新窗口 ctrl+Page Down 所有vim窗口向下切换 ctrl+ ...