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. Windows 10文件夹Shirt+鼠标右键出现“在此处打开命令窗口”

    Windows 10文件夹Shirt+鼠标右键出现“在此处打开命令窗口” Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\Directo ...

  2. leetcode-58.最后一个单词的长度

    leetcode-58.最后一个单词的长度 题意 给定一个仅包含大小写字母和空格 ' ' 的字符串,返回其最后一个单词的长度. 如果不存在最后一个单词,请返回 0 . 说明:一个单词是指由字母组成,但 ...

  3. 转载:python生成以及打开json、csv和txt文件

    原文地址:https://blog.csdn.net/weixin_42555131/article/details/82012642 生成txt文件: mesg = "hello worl ...

  4. HDU 2086 A1 = ? (找规律推导公式 + 水题)(Java版)

    Equations 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2086 ——每天在线,欢迎留言谈论. 题目大意: 有如下方程:Ai = (Ai-1 ...

  5. 学习用Node.js和Elasticsearch构建搜索引擎(6):实际项目中常用命令使用记录

    1.检测集群是否健康. curl -XGET 'localhost:9200/_cat/health?v' #后面加一个v表示让输出内容表格显示表头 绿色表示一切正常,黄色表示所有的数据可用但是部分副 ...

  6. Linux中Root密码破解

    1.开机后在选择菜单时按下e进入编辑模式 2.选择linux16这一行,在行末尾添加 rd.break 3.然后Ctrl+x执行.然后进入shell界面: 4.设置密码: 1.重新挂载根目录为读写模式 ...

  7. vs2017 代码格式化 文档排版 编辑 设置文档的格式

    vs

  8. gcc5.4报错对‘std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string()’未定义的引用

    我在编译ligra是遇到了这个问题,网上搜了一遍,发现是了原因https://gcc.gnu.org/onlinedocs/libstdc%2B%2B/manual/using_dual_abi.ht ...

  9. LeetCode算法题-Valid Palindrome(Java实现)

    这是悦乐书的第174次更新,第176篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第33题(顺位题号是125).给定一个字符串,确定它是否是回文,只考虑字母数字字符并忽略 ...

  10. android开发——用户头像

    最近,小灵狐得知了一种能够加快修炼速度的绝世秘法,那便是修炼android神功.小灵狐打算用android神功做一个app,今天他的修炼内容就是头像功能.可是小灵狐是个android小白啊,所以修炼过 ...