• 互斥同步


    互斥同步

      java提供了两种锁机制来控制多个线程对共享资源的互斥访问,第一个是jvm实现的synchronized,而另一个是jdk实现的ReentrantLock

    synchronized

    1.同步一个代码块

    public void func() {
        synchronized (this) {
            // ...
        }
    }
    

      它只作用于同一个对象,如果调用两个对象以上的同步代码块,就不会进行同步。

      对于以下代码,使用ExecutorSrevice执行了两个线程,由于调用的是同一个对象的同步代码块,那么线程会进行同步,当一个线程进入同步语句块的时候,另一个线程就不能进入。

    import java.util.concurrent.*;
    public class SynchronizedExemple{
        private static class  SychronizedExempleClass{
            public void fun(){
                synchronized(this){
                    for(int i=0;i<10;i++){
                        System.out.println(i);
                    }
                }
            }
        }
        public static void main(String[]args){
            ExecutorService executorService=Executors.newCachedThreadPool();
            SychronizedExempleClass e=new SychronizedExempleClass();
            executorService.execute(()->e.fun());
            executorService.execute(()->e.fun());
            executorService.shutdown();
    
        }
    }
    

    2.同步一个方法

      同步一个方法时和同步一个代码块相同,作用于同一个对象

    public synchronized void fun(){
        //....
    }
    

    3.同步一个类

      作用于整个类,所以说两个线程调用同一个类的不同对象上的这种同步语句,同样会进行同步。

    public void fun(){
        synchronized(SynchronizedExemple.class){
            //....
        }
    }
    

      下面代码调用两个线程访问两个不同对象的同步代码区。

    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class SynchronizedClassExemple {
        private static class SynchronClass{
            public void fun(){
                synchronized (SynchronClass.class){
                    for(int i=0;i<10;i++)
                        System.out.println(i);
                }
            }
        }
        public static void main(String[]args){
            SynchronClass e1=new SynchronClass();
            SynchronClass e2=new SynchronClass();
            ExecutorService executorService= Executors.newCachedThreadPool();
            executorService.execute(()->e1.fun());
            executorService.execute(()->e2.fun());
            executorService.shutdown();
        }
    }
    
    

    4.同步一个静态方法

    public synchronized void fun(){
        //..
    }
    

      作用于整个类。

    ReentrantLock

      ReentrantLock是java.until.concurrent(J.U.C)包中的锁。

    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class ReentrantLockExemple {
        private  static  class LockExemple{
            Lock lock=new ReentrantLock();
            public void fun(){
                lock.lock();  //上锁
                try{
                    for(int i=0;i<10;i++){
                        System.out.println(i);
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }finally {
                    lock.unlock();  //解锁
                }
            }
    
        }
        public static void main(String[]args){
            LockExemple e=new LockExemple();
            ExecutorService executorService= Executors.newCachedThreadPool();
            executorService.execute(()->e.fun());
            executorService.execute(()->e.fun());
            executorService.shutdown();
        }
    }
    
    

    两种锁的比较

    1.锁的实现

      synchronized是JVM实现的,而ReentrantLock是J.U.C实现的。

    2.性能

      新版本的java对synchronized进行了许多的优化,例如自旋锁偏向锁,等。与ReentrantLock大致相同。

    3.等待可中断

      当持有锁的线程长期不释放锁的时候,正在等待的线程可以选择放弃等待,改为处理其他事情。ReentrantLock 可中断,而 synchronized 不行

    4.公平锁

      公平锁值得是多个线程在等待同一个锁时,必须按照申请锁的时间顺序来依次获得锁synchronized锁是非公平的,而ReentrantLock 默认情况下也是非公平的,但是也可以是公平的

    5.锁绑定多个条件

    ​ 一个 ReentrantLock 可以同时绑定多个 Condition 对象。

    使用选择

      除非需要使用 ReentrantLock 的高级功能,否则优先使用 synchronized。这是因为 synchronized 是 JVM 实现的一种锁机制,JVM 原生地支持它,而 ReentrantLock 不是所有的 JDK 版本都支持。并且使用 synchronized 不用担心没有释放锁而导致死锁问题,因为 JVM 会确保锁的释放,但是使用ReentrantLock灵活度更高

  • 相关阅读:
    CSS3 渐变 透明 圆角
    使用JSON作为函数的参数(转载)
    如何让输入的单词首字母大写
    mysql 修改表/字段 增加/删除表索引
    Jquery Mobile 客户端验证
    如何写出漂亮的js代码(转载)
    GoogleMap添加一个Marker
    Log4j的使用【转载】
    Google Map 自定义infowindow
    MYSQL重装出现could not start the service mysql error:0处理(已验证可以使用)
  • 原文地址:https://www.cnblogs.com/yjxyy/p/10703380.html
Copyright © 2020-2023  润新知