`
uule
  • 浏览: 6350294 次
  • 性别: Icon_minigender_1
  • 来自: 一片神奇的土地
社区版块
存档分类
最新评论

Synchronized关键字总结

阅读更多

1、synchronized关键字的作用域有二种:
  1)是某个对象实例内,synchronized aMethod(){} 可以防止多个线程同时 访问这个对象的synchronized方法 (如果一个对象有多个synchronized方法,只要一个线程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法 )。这时,不同的对象实例的 synchronized方法是不相干扰的。也就是说,其它线程照样可以同时访问相同类的另一个对象实例中的synchronized方法;
      总的来说,这种情况,锁就是这个方法所在的对象

  2)是某个类的范围,synchronized static aStaticMethod{} 防止多个线程同时访问这个类中的synchronized static 方法 。它可以对类的所有对象实例起作用。此时锁就是这个class

2、除了方法前用synchronized关键字,synchronized关键字还可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。
   用法是: synchronized(this){/*区块*/},锁就是这个方法所在的对象 ;

3、synchronized关键字是不能继承的,也就是说,基类的方法synchronized f(){} 在继承类中并不自动是synchronized f(){},而是变成了f(){}。继承类需要你显式的指定它的某个方法为synchronized方法;
 
4、无论synchronized关键字加在方法上还是对象上,它取得的锁都是对象,而不是把一段代码或函数当作锁――而且同步方法很可能还会被其他线程的对象访问。
   每个对象只有一个锁(lock)与之相关联。
   实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。

1、理论上,每个对象都可以做为锁,但一个对象做为锁时,应该被多个线程共享,这样才显得有意义,在并发环境下,一个没有共享的对象作为锁是没有意义的 。假如有这样的代码:

 public class ThreadTest{  
   public void test(){  
      Object lock=new Object();  
      synchronized (lock){  
         //do something  
      }  
   }  
 } 

 lock变量作为一个锁存在根本没有意义,因为它根本不是共享对象,每个线程进来都会执行Object lock=new Object();每个线程都有自己的lock,根本不存在锁竞争。

2、为了保证银行账户的安全,可以操作账户的方法如下:

public synchronized void add(int num) {  
      balance = balance + num;  
 }  
 public synchronized void withdraw(int num) {  
      balance = balance - num;  
 }  

 每个锁对象都有两个队列,一个是就绪队列,一个是阻塞队列,就绪队列存储了将要获得锁的线程,阻塞队列存储了被阻塞的线程,当一个被线程被唤醒 (notify)后,才会进入到就绪队列,等待cpu的调度。当一开始线程a第一次执行account.add方法时,jvm会检查锁对象account 的就绪队列是否已经有线程在等待,如果有则表明account的锁已经被占用了,由于是第一次运行,account的就绪队列为空,所以线程a获得了锁,执行account.add方法。如果恰好在这个时候,线程b要执行account.withdraw方法,因为线程a已经获得了锁还没有释放,所以线程 b要进入account的就绪队列,等到得到锁后才可以执行。
参考:http://www.iteye.com/topic/806990
      http://blog.csdn.net/suchfool/archive/2011/01/11/6129833.aspx

 

3、

    public class SyncBlock
    {
        public void method1()
        {
            synchronized(this)  // 相当于对method1方法使用synchronized关键字
            {
                … …
            }
        }
        public void method2()
        {
            synchronized(this)  // 相当于对method2方法使用synchronized关键字
            {
                … …
            }
        }
        public synchronized void method3()  
        {
            … …
        }
    }

  在使用同一个SyncBlock类实例时,这三个方法只要有一个正在执行,其他两个方法就会因未获得同步锁而被阻塞。在使用synchronized块时要想达到和synchronized关键字同样的效果,必须将所有的代码都写在synchronized块中 ,否则,将无法使当前方法中的所有代码和其他的方法同步。

    除了使用this做为synchronized块的参数外,还可以使用ClassName.class(本例为 SyncBlock.this )作为synchronized块的参数来达到同样的效果。

    在内类(InnerClass)的方法中使用synchronized块来时,this只表示内类,和外类(OuterClass)没有关系。但内部类的非静态方法可以和外类的非静态方法同步 。如在内类InnerClass中加一个method4方法,并使method4方法和SyncBlock的三个方法 同步,代码如下:

public class SyncBlock
{
    ...
    class InnerClass
    {
        public void method4()
        {
            synchronized(SyncBlock.this)
            {  ...   }
        }
    }
}

 该例中,InnerClass类的method4方法和SyncBlock类的其他三个方法同步,因此,method1、method2、method3和method4四个方法在同一时间只能有一个方法执行。

静态内部类可以直接创建对象new B.C();
如果内部类不是静态的,那就得这样
B b = new B();
B.C c = b.new C();

 

    Synchronized块不管是正常执行完,还是因为程序出错而异常退出synchronized块,当前的synchronized块所持有的同步锁都会自动释放 。因此,在使用synchronized块时不必担心同步锁的释放问题。

 

4、sychronized关键字只和一个对象实例绑定

  class Test
  {
       public synchronized void method()
       {   }
  }
   
  public class Sync implements Runnable
  {
       private Test test;

       public Sync(Test test)
       {
           this.test = test;
       }

       public void run()
       {
            test.method();
       }
       
       public static void main(String[] args) throws Exception
       {
           Test test1 =  new Test();
           Test test2 =  new Test();
           Sync sync1 = new Sync(test1);
           Sync sync2 = new Sync(test2);
           new Thread(sync1).start();
           new Thread(sync2).start(); 
       }
   }

 上面的代码建立了两个Test类的实例,因此,test1和test2的method方法是分别执行的。要想让method同步,必须在建立Sync类的实例时向它的构造方法中传入同一个Test类的实例。

 

Synchronized与ThreadLocal的区别:

ThreadLocal:http://uule.iteye.com/admin/blogs/870464

一、
synchronized关键字主要解决多线程共享数据同步问题
ThreadLocal使用场合主要解决多线程中数据因并发产生不一致问题

ThreadLocal和Synchonized都用于解决多线程并发访问 。但是ThreadLocal与synchronized有本质的区别:

 synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问而ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享 。而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享。

Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。当然ThreadLocal并不能替代synchronized,它们处理不同的问题域。Synchronized用于实现同步机制,比ThreadLocal更加复杂。

ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很简单,在ThreadLocal类中有一个Map,用于存储每一个线程的变量的副本。
概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。

二、API说明

ThreadLocal()
 创建一个线程本地变量。

T get()
 返回此线程局部变量的当前线程副本中的值,如果这是线程第一次调用该方法,则创建并初始化此副本。

protected T initialValue()
 返回此线程局部变量的当前线程的初始值。最多在每次访问线程来获得每个线程局部变量时调用此方法一次,即线程第一次使用 get() 方法访问变量的时候。如果线程先于 get 方法调用 set(T) 方法,则不会在线程中再调用 initialValue 方法。
 若该实现只返回 null;如果程序员希望将线程局部变量初始化为 null 以外的某个值,则必须为 ThreadLocal 创建子类,并重写此方法。通常,将使用匿名内部类。initialValue 的典型实现将调用一个适当的构造方法,并返回新构造的对象。

void remove()
 移除此线程局部变量的值。这可能有助于减少线程局部变量的存储需求。如果再次访问此线程局部变量,那么在默认情况下它将拥有其 initialValue。

void set(T value)
 将此线程局部变量的当前线程副本中的值设置为指定值。许多应用程序不需要这项功能,它们只依赖于 initialValue() 方法来设置线程局部变量的值。
 在程序中一般都重写initialValue方法,以给定一个特定的初始值。

总结:
 
 ThreadLocal为每个线程的中并发访问的数据提供一个副本,通过访问副本来运行业务,这样的结果是耗费了内存 ,但大大减少了 线程同步所带来性能消耗 ,也减少了线程并发控制的复杂度。

ThreadLocal使用的一般步骤:
 1、在多线程的类(如ThreadDemo类)中,创建一个ThreadLocal对象threadXxx,用来保存线程间需要隔离处理的对象xxx。
 2、在ThreadDemo类中,创建一个获取要隔离访问的数据的方法getXxx(),在方法中判断,若ThreadLocal对象为null时候,应该new()一个隔离访问类型的对象,并强制转换为要应用的类型。
 3、在ThreadDemo类的run()方法中,通过getXxx()方法获取要操作的数据,这样可以保证每个线程对应一个数据对象,在任何时刻都操作的是这个对象。

分享到:
评论

相关推荐

    synchronized关键字的用法详解

    ### synchronized关键字的深入解析 #### 一、synchronized关键字的重要性 `synchronized`关键字在Java语言中扮演着极其重要的角色,它是实现线程安全的核心手段之一。通过`synchronized`关键字,开发人员可以在多...

    java基本教程之synchronized关键字java多

    一、synchronized关键字的作用与原理 `synchronized`关键字主要有两个作用:同步方法和同步块。它通过锁机制来实现线程同步,防止多个线程同时执行同一段代码,可能导致的数据不一致问题。 1. 同步方法:当在方法...

    synchronized关键字的实质及用法

    《深入理解Java中的synchronized关键字》 在Java编程语言中,`synchronized`关键字是用于实现线程同步的重要工具,它的本质在于确保多线程环境下的数据一致性与安全性。通过`synchronized`,我们可以控制对共享资源...

    Lock接口与synchronized关键字

    ### Lock接口与synchronized关键字详解 #### 一、概述 在Java并发编程中,Lock接口与synchronized关键字都是实现同步的重要工具。它们虽然都用于控制多线程对共享资源的访问,但在使用方式、功能特性及灵活性方面...

    深入理解java中的synchronized关键字

    总结来说,`synchronized`关键字在Java中扮演着至关重要的角色,它是保证多线程环境下数据一致性的重要工具。通过合理使用synchronized方法和synchronized块,开发者可以有效地控制并发访问,防止数据竞争问题,确保...

    java synchronized关键字原理、自定义一把锁来实现同步等

    ### Java synchronized 关键字原理与自定义锁实现详解 #### 一、Java synchronized 关键字原理 `synchronized` 是 Java 中的关键字之一,用于实现线程间的同步控制,确保共享资源的安全访问。它主要应用于以下两种...

    举例讲解Java中synchronized关键字的用法

    总结来说,`synchronized`关键字在Java中用于实现线程同步,防止数据竞争,确保多线程环境下的安全性。它可以通过修饰方法或代码块来指定锁对象,根据场景选择合适的同步策略对于优化并发性能至关重要。在实际编程中...

    并发编程原理学习:synchronized关键字.doc

    并发编程是多线程环境下确保程序正确性的关键技术,而Java中的`synchronized`关键字则是实现并发控制的重要工具。`synchronized`关键字可以用于修饰方法或作为同步代码块,其核心目标是保证线程对共享资源的访问具有...

    Java多线程synchronized关键字详解(六)共5

    总结来说,`synchronized`关键字在Java多线程编程中扮演着关键角色,确保了线程安全和数据一致性。然而,正确理解和使用它是至关重要的,避免滥用并结合其他并发控制手段,才能编写出高效且健壮的多线程程序。在实际...

    java关键字总结

    以上是Java中的主要关键字总结,每个关键字都在不同的场景下发挥着重要作用,理解并熟练掌握这些关键字对于编写高效、可靠的Java代码至关重要。对于更深入的学习,可以参考指定的博文链接或其他相关资料进行研究。

    Java中使用synchronized关键字实现简单同步操作示例

    总结起来,`synchronized`关键字在Java中扮演着重要的角色,它提供了线程安全的保证,避免了并发环境下的数据不一致问题。根据具体需求,可以选择合适的方式使用`synchronized`关键字,以确保同步的粒度和效率。需要...

    Java中synchronized关键字修饰方法同步的用法详解

    【Java中synchronized关键字修饰方法同步的用法详解】 在Java多线程编程中,synchronized关键字是一个重要的同步工具,它能确保共享资源在多线程环境下的安全访问。synchronized可以用来同步静态和非静态方法,从而...

    java多线程编程之Synchronized关键字详解

    总结来说,`Synchronized`关键字在Java多线程编程中起到关键的同步作用,通过对象锁来确保共享资源的安全访问。然而,过度使用或不恰当使用可能导致程序并发性能下降。因此,合理地设计同步策略,结合其他并发工具如...

    JAVA关键字总结(整理后最全最详细)

    下面是对Java关键字的详细总结,按照给出的部分内容进行排列: 1. `abstract`: - `abstract` 关键字用于声明抽象类或抽象方法。抽象类不能被实例化,只能作为其他类的基类。抽象方法没有具体的实现,必须在子类中...

    Java-synchronized详解.docx

    在 Java 中,同步机制是通过 synchronized 关键字实现的。synchronized 可以用于方法或代码块,以确保在同一时间只有一个线程可以访问该方法或代码块。这样可以防止多个线程同时访问共享资源,避免数据不一致和 race...

    java_synchronized详解

    #### 一、synchronized关键字简介 `synchronized`是Java语言提供的关键字之一,用于实现线程间的同步控制。通过在方法或代码块上使用`synchronized`,可以确保同一时间只有一个线程能访问这些代码区域,从而有效避免...

    Java关键字总结珍藏版(48个).doc

    38. `synchronized`:`synchronized` 用于线程同步,确保同一时间只有一个线程可以访问特定代码块。 39. `this`:`this` 关键字引用当前对象实例。 40. `throw`:`throw` 用于抛出一个异常。 41. `throws`:`...

    synchronized与单例的线程安全

    总结来说,synchronized关键字和单例模式在Java中都是保证线程安全的有效手段。synchronized用于控制多线程对共享资源的访问,而单例模式则保证类只有一个实例,防止多线程环境下的资源冲突。在实际开发中,应根据...

    Java多线程-知识点梳理和总结-超详细-面试知识点.docx

    本文从Java多线程的基本概念开始,逐步深入到Java多线程的高级话题,涵盖了Java多线程的所有方面,包括volatile关键字、Java内存模型、Happens-Before关系、synchronized关键字、ConcurrentHashMap、...

Global site tag (gtag.js) - Google Analytics