我所理解的多线程之synchronized

接触到JAVA以及有很长一段时间了,平时也没有什么时间写博客,现在把平时工作中所做的笔记贴出来供大家参考一下
synchronized关键字想必接触过java多线程的同学都知道,主要作用是对某一特定代码加锁,使得同一时间只能由一条线程访问它。但是这个锁到底是锁什么东西呢?
其实synchronized很简单,没必要被多线程这个概念吓坏了。这个锁,就是锁当前被访问的代码而已。我举例说明。
1.方法锁
方法锁,顾名思义就是锁住一个方法,使得同一个实例(不同实例可以同时访问)同时只能有一条线程访问它。
    public synchronized void method(){
       //do sth..
    }
这是比较简单而且容易理解的方式。
2.类锁
类锁,一般是针对类中的静态变量(static)而言,同一个类中,即使是不同的对象也不能同时访问。
    public  synchronized static void method(){
       // do sth..
    }
在单例模式中经常会用到这种写法。
3.对象锁
在实际运用当中,方式1虽然很便捷,但在高并发的环境下,对整个方法加锁并不是一个理想的方式。如果执行这个方法需要1秒钟,那么第1000个访问这个方法的线程就要等1*1000秒,明显不能这么处理。那该如何解决呢?这就要用到对象锁了,在特定代码块对一个对象进行加锁。
    public void method(obj){
       synchronized (obj){
           //do sth..
       }
    }
很多情况下obj并不会是同一个对象。比如你用hibernate从数据库中取出一个对象,另一条线程中也通过hibernate取出了这个对象,虽然这两个对象指向的数据是同一条,但它们对应的hashcode并不是同一个,因此JVM认为它们不是同一个对象,所以刚刚那条代码并不能对这条数据成功加锁。那该如何解决呢?
我们可以通过ConcurrentHashMap来保存这个对象的ID,在代码中对这个ID加锁即可。
public class MultiThreadTs {
    private static ConcurrentHashMap<Integer,Object> map=new ConcurrentHashMap<Integer, Object>();
    public void method(){
        try{
            synchronized (setAndGet(对象的ID)){
                //do sth..
            }
        }finally {
            remove(对象的ID);
        }

    }
    private Object setAndGet(Integer id){
        map.putIfAbsent(id,new Object());
        return map.get(id);
    }

    private void remove(Integer id){
        map.remove(id);
    }
}
在上面那段代码中,我们为什么不能直接用synchronized(对象的ID)来加锁呢?因为在实际生产环境中,两个整型对象Integer虽然他们具有相同的值,但它们有可能并不是同一个对象,所以要使用ConcurrentHashMap来确保同一个ID下的对象是相同的,这样程序才能成功锁住它。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章