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)

 

posted @ 2017-12-09 16:04  china2k  阅读(723)  评论(0编辑  收藏  举报