• 实现线程同步的几种方式


    synchronized关键字修饰的方法实现同步

    1.在方法级别  public synchronized ….

    内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。

    注: synchronized关键字也可以修饰静态方法,此时如果调用该静态方法,将会锁住整个类

    2.同步代码块   synchronized(对象){}

    即有synchronized关键字修饰的语句块。 

    通常没有必要同步整个方法,使用synchronized代码块同步关键代码即可。

    /**
                 * 用同步代码块实现
                 * 
                 * @param money
                 */
                public void save1(int money) {
                    synchronized (this) {
                        account += money;
                    }
                }

    1.当synchronized作用在方法上的时候,锁住的就是这个对象的实例 synchronized(this). 

    2.当一个线程访问synchronized(this) 同步块时, 另一个线程仍然可以访问当前对象内的非synchroinzed(this)同步块代码

    3.同步是一个耗性能的操作,因此我们尽量减少同步的内容,最好不要加载整个方法上

    3.给对象加锁

    当有一个明确的对象作为锁时,就可以用类似下面这样的方式写程序。

    public void method3(SomeObject obj)
    {
       //obj 锁定的对象
       synchronized(obj)
       {
          // todo
       }
    }

    用synchronized 给account对象加了锁。这时,当一个线程访问account对象时,其他试图访问account对象的线程将会阻塞,直到该线程访问account对象结束。也就是说谁拿到那个锁谁就可以运行它所控制的那段代码。

     4.修饰一个静态的方法

    public synchronized static void method() {
       // todo
    }

    静态方法是属于类的而不属于对象的。同样的,synchronized修饰的静态方法锁定的是这个类的所有对象。

    当synchronized修饰静态方法的时候, 同步对象就是这个类的类对象

    如代码中的例子,当第一个线程进入method1的时候,需要占用TestReflection.class才能执行。

    第二个线程进入method2的时候进去不了,只有等第一个线程释放了对TestReflection.class的占用,才能够执行。 反推过来,第二个线程也是需要占用TestReflection.class。 那么TestReflection.class就是method2的同步对象。

    5. 修饰一个类

    class ClassName {
       public void method() {
          synchronized(ClassName.class) {
             // todo
          }
       }
    }

    给class加锁和上例的给静态方法加锁是一样的,所有对象公用一把锁

    第二种:(volatile)实现线程同步 

    volatile关键字为域变量的访问提供了一种免锁机制

    只需在account前面加上volatile修饰,即可实现线程同步。

    class Bank {
                //需要同步的变量加上volatile
                private volatile int account = 100;
    
                public int getAccount() {
                    return account;
                }
                //这里不再需要synchronized 
                public void save(int money) {
                    account += money;
                }
            }

    1.多线程中的非同步问题主要出现在对域的读写上,如果让域自身避免这个问题,则就不需要修改操作该域的方法。

    2.volatile不能保证原子操作,因此volatile不能代替synchronized

    3.每次要线程要访问volatile修饰的变量时都是从内存中读取,而不是从缓存当中读取,因此每个线程访问到的变量值都是一样的。这样就保证了同步。

    java.util.concurrent包来支持同步

  • 相关阅读:
    MyEclipse中的几种查找方法
    WebLogic初学笔记
    CountDownLatch源码分析
    linux--句柄相关
    linux命令--wc
    Spring源码解析(九)--再来说说三级缓存
    定位JVM内存泄漏常用命令和方法
    Mybatis整合Spring之MapperFactoryBean怎么拿到的SqlSessionFactory
    Mybatis3.3.0 Po类有LocalDateTime字段报错
    时间范围查询优化技巧
  • 原文地址:https://www.cnblogs.com/volvane/p/9394266.html
Copyright © 2020-2023  润新知