zoukankan      html  css  js  c++  java
  • [03] 线程同步 synchronized


    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
    ...

    如上例中,可以看到在 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
    ...

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


  • 相关阅读:
    CREATE AGGREGATE
    技术文档列表
    jQuery 判断表单中多个 input text 中至少有一个不为空
    Java实现 蓝桥杯 算法提高 奥运会开幕式
    Java实现 蓝桥杯 算法提高 最长滑雪道
    Java实现 蓝桥杯 算法提高 最长滑雪道
    Java实现 蓝桥杯 算法提高 最长滑雪道
    Java实现 蓝桥杯 算法提高 最大值路径
    Java实现 蓝桥杯 算法提高 最大值路径
    Java实现 蓝桥杯 算法提高 最大值路径
  • 原文地址:https://www.cnblogs.com/deng-cc/p/9462739.html
Copyright © 2011-2022 走看看