zoukankan      html  css  js  c++  java
  • java并发-锁-synchromized

    关键字synchromized 的作用是实现线程间的同步。它的工作室对同步的代码加锁,使得每一,只有一个线程可以进入同步块,从而保证线程间的安全性。

    synchromized 的用户这里做一个简单的整理,

    1,指定加锁对象:对给定对象加锁,进入同步代码前要获得给定对象的锁。

    2,直接作用于实例方法:相当于对当前实例加锁,进入同步代码前要获得当前实例的锁。

    3,直接作用于静态方法:相当于对当前类加锁,进入同步代码前要获得当前类的锁。

    如下面一段代码给制定对象加锁:

    public class Test implements Runnable {
        static Object lock = new Object();
        static int i = 0;
        @Override
        public void run() {
            for (int j = 0; j < 100000; j++) {
                synchronized (lock) {
                    i++;
                }
            }
        }
        public static void main(String args[]) throws InterruptedException {
            Test test = new Test();
            Thread thread1 = new Thread(test);
            Thread thread2 = new Thread(test);
            thread1.start();
            thread2.start();
            thread1.join();
            thread2.join();
            System.out.println(i);
        }
    }

    当然上面代码也可将synchromized关键字作用于实例方法上:

    public class Test implements Runnable {
        static int i = 0;
        public synchronized void increase(){
            i++;
        }
        @Override
        public void run() {
            for (int j = 0; j < 100000; j++) {
                increase();
            }
        }
        public static void main(String args[]) throws InterruptedException {
            Test test = new Test();
            Thread thread1 = new Thread(test);
            Thread thread2 = new Thread(test);
            thread1.start();
            thread2.start();
            thread1.join();
            thread2.join();
    
            System.out.println(i);
        }
    }

    同时这里一定要注意的是Thread的创建方式,这里Test类只new一个实例 ,因为synchronized 直接作用于实例方法,需要线程指向同一个实例,才能保证多线程使用的是同一个锁。

    如果使用了下面的方式,那么就会产生两个Test实例,thread1和thread2也就获得了不同的锁,所以synchronized 作用于实例方法时,需要保证创建线程是同一个Runnable接口实例。

    Thread thread1 = new Thread(new Test());
    Thread thread2 = new Thread(new Test());

    当然,使用synchronized 第三种方式将其作用于静态方法,就没有问题了

     public static synchronized void increase(){
            i++;
        }

    其他,synchronized的使用个人觉得对对象加锁的方式是优于对实例方法的使用,

    当某个线程进入同步方法获得对象锁,那么其他线程访问这里对象的同步方法时,必须等待或者阻塞,这对高并发的系统是致命的,这很容易导致系统的崩溃。如果某个线程在同步方法里面发生了死循环,那么它就永远不会释放这个对象锁,那么其他线程就要永远的等待。

    下面是jdk对hash的实现方式,可以看到,很多方法都是使用了 synchronized 进行了修饰,那么就意味如果还有别的同步方法x,这个x方法和get方法即使在没有冲突的情况下也需要等待执行(比如有3个线程同时做读操作,实际上是不需要阻塞,可以同时进行的)。这样效率上 必然会有一定的影响,所以会有 ConcurrentHashMap 进行分段加锁

    public synchronized V get(Object key) {
            Entry<?,?> tab[] = table;
            int hash = key.hashCode();
            int index = (hash & 0x7FFFFFFF) % tab.length;
            for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
                if ((e.hash == hash) && e.key.equals(key)) {
                    return (V)e.value;
                }
            }
            return null;
        }
    
    public synchronized V put(K key, V value);
    public synchronized V remove(Object key)
  • 相关阅读:
    [HDU1087]Super Jumping! Jumping! Jumping!<dp>
    [codeforces]Page Numbers <模拟>
    [POJ1190]生日蛋糕<DFS>
    [HDU1029]Ignatius and the Princess IV<桶 水题>
    矩阵优化
    康复式训练
    bzoj1036 [ZJOI2008]树的统计Count
    luogu3761 [TJOI2017]城市
    bzoj2282 [SDOI2011]消防
    NOI2014
  • 原文地址:https://www.cnblogs.com/china2k/p/8011734.html
Copyright © 2011-2022 走看看