您的位置:首页 > 百科 > 正文

synchronized

synchronized 关键字,代表这个方法加锁,相当于不管哪附永屋一个线程(例来自如线程A),运行到这个方法时,都要检查有没有其它线程B(字点先沙略皇或者C、 D等)正在用这个方法(或者360百科该类的其他同步方法),有的话要等正在使用synchronized方法的线程B(或者C 、D)运行完这个方法后再运行此线程A,没有的话,锁定调用者,然后直接运行。它包括两种用法:synchronized 方牛微告谈这举将状法和 synchronized 块。

Java语言的关键字,可用来给对象和方量整销科卷当法或者代码块加锁,况衡于当它锁定一个方法或者一个代码块的时候,同一时刻最多只刑苦钟镇三孔含击害有一个线程执行这段代征离著晚与准部巴码。当两个并发线程访问同一个对象object中的这个加锁同步代码块时,一个时间谁合剂路飞危丝内只能有一个线程得到执行。另一型找掉殖个线程必须等待当前线程圆谓线执行完这个代码块以练知后露测久色后才能执行该代码块。然而,当一个线程访问object的一个加锁代码块时,另一个线程仍可以访问该object中的非加锁代码块。

  • 中文名称 Java语言的关键字
  • 外文名称 synchronized
  • 代表 方法加锁
  • 方法声明 放在范围操作符
  • 英式发音 英['sɪŋkrənaɪzd]

  synchronized 方法

  1.方法声明时使用,放在范围操作符(public等)之后,返回类型声明(void等)之前.这时,线程获得的是成员锁,即一次只能有一个线程进入该方来自法,其他线程要想在此时调用该方再定采法,只能排队等候,当前线程(就是在synchronized方法内部的线程)执行完该方法后,别的线程才能进入.

  例如:

  如在线程t1中有讲套院催语句拘雅危obj.synMethod(); 那么由于synMeth360百科od被synchronized修饰,在执行该语句前, 需要先获得调用者obj的对象锁, 如果其他规做间线宙弃去程(如t2)已经锁定了obj (可能是通过obj.synMethod,也可能是通过其他被synchronized修饰的方法obj.otherSyn造会运Method锁定的obj), t1需要等待直到其他线程(t2)释马队放obj, 然后t1锁定obj, 执行synMethod方法. 返回烧立单短元脸别肥之前释放obj锁.

  2.对某一代码块使用,synchronized后跟趋备愉括号,括号里是变量,这样,一次只有一个轮船其尽线程进入该代码块.此时,线程获得的是成员锁.例如:

  3.synchronized后面括号里是一对象吗移革站学宽变妈,此时辨断剃乎,线程获得的径文且仅台新似站神雷是对象锁.例如:

  对于3,如果线程进入,则得到当前对象锁,那么别的线程在该类所有对象上的任界非书考级呀食路由何操作都不能进行.在对象级使用锁通常是一种比较粗糙的方法。为什么要将整个对象都上锁,而不允许其他线程短暂地使用对象中其他同步方法来谅邀访问共享资源?如果一个对象拥有多个资源,就不需要只为了让一个线程使用其中一部分资源,就将所有线程都锁在外面。由于每个对象都有锁,可以如下所示使用虚拟对象来上锁:

  4.synchronized后面括号里是类,此时,线程获得的是对象锁.例如:

  对于4油秋判明放,如果线程进入,则线程在该类中所有操作不能进行,包括静态变量和静态方法,实际上,对于含有静态方调争士路蛋冷法和静态变量的代码块的同步,我们通常用4来加锁.

理解

  一、当什甲跟利什犯轮促两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当查帝前线程执行完这个代码块以后才能执行该代码块。

  二、然而,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。

  三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同革触步代码块的访问将被阻塞。

  四、第三个例子同样适用其它同步代码块,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。

  五、以上规则对其它对象锁同样适用。

用法

  1.方法声明时使来自用,放在范围操作符(public等)后,其返回类型声明(void等)之前。即一次只能有一个线程进入该方法,其他线程要想在此360百科时调用该方法,只能排队等候,当前线程(就是在synchronized方法家胜盾内部的线程)执行完该方法后,别的线程才能进入。

  例如:

  public synchronized void synMethod(应鸡) {

  //方法体

  }

  2.对某一代码块使用,synchronized后跟括号,括号里是变量,这样,一次只有一个线程进入该代码块。例如:

  public int synMethod(Object a1){

  synchronized(Object) {

  //一次只能有一个线程进入

  }

  }

  3.synchronized后面括号里是一对象,此时,线程获得的是对象锁。例如:

  public class MyThread implements 措左客督田块唱使父皮Runnable {

  public static void main(String args[]) {

  MyThread mt = n胞煤王强官策约功针ew MyThread();

 部构围胜过怎措算讲州资 Thread t1 = new Thread(mt神台零随必处急虽, "t1");

  Thread t2 = new Th刚秋read(mt, "t2");

  Thread t3 = new Thread(mt, "t3");

  Thread t4 = new Thread(mt, "t4");

  Thread t5 = new Thread(mt, "t5");

  Thread t6 = new Thread(度鲁银罗仍mt, "t6");

  t1.start胞阿责类读内误密继();

  t2.start();

  t3.start();

  t4.start();

  t5.start答院国响罪小叶青离();

  t6.start();

  }

  public void run() {

  synchronized (this) {

  System.out.println(Th陆字己精read.currentThread().getName());

  }

  }

  }

  对于3,如果线程进入,则得到对象锁,那么别的线程在该类所有对象上的任何操作都不能进行。在对象级使用锁通常是一种比较粗糙的局合读破顺装亮用方法。为什么要将整个对象都上锁,而不允许其他线程短暂地使用对象中其他同步方法来访问共享资源?如果一个对象拥有多个资源,就不需要只为了让一个线程使用其中一部分资源,就将所有线程都锁在块回已候土制突外面。由于每个对象都有锁,可以如下所示使用虚拟对象来上锁:

  clas宽混应命点晶为刻红烟编s FineGrainLock {

  MyMemberClass x, y;

  Object xlock = new Object(), ylock = new Object();

  public void 均胡胞价务建较foo() {

  synchronized(xlock) {

  //access x here

愿曲  }

  //do someth垂仅真扬ing here - but don't use shared resources

  synchronized(ylock) {

  //access y here

  }

  }

  public void bar() {

  synchronized(this) {

  //access both x and y here

  }

  //do something here - but don't use shared resources

  }

  }

  4.synchronized后面括号里是类。例如:

  class ArrayWithLockOrder{

  private static long num_locks = 0;

  private long lock_order;

  private int[] arr;

  public ArrayWithLockOrder(int[] a)

  {

  arr = a;

  synchronized(ArrayWithLockOrder.class) {//-----------------------------------------这里

  num_locks++; // 锁数加 1。

  lock_order = num_locks; // 为此对象实例设置唯一的 lock_order。

  }

  }

  public long lockOrder()

  {

  return lock_order;

  }

  public int[] array()

  {

  return arr;

  }

  }

  class SomeClass implements Runnable

  {

  public int sumArrays(ArrayWithLockOrder a1,

  ArrayWithLockOrder a2)

  {

  int value = 0;

  ArrayWithLockOrder first = a1; // 保留数组引用的一个

  ArrayWithLockOrder last = a2; // 本地副本。

  int size = a1.array().length;

  if (size == a2.array().length)

  {

  if (a1.lockOrder() > a2.lockOrder()) // 确定并设置对象的锁定

  { // 顺序。

  first = a2;

  last = a1;

  }

  synchronized(first) { // 按正确的顺序锁定对象。

  synchronized(last) {

  int[] arr1 = a1.array();

  int[] arr2 = a2.array();

  for (int i=0;i<size;i++)value += arr1[i] + arr2[i];

  }

  }

  }

  return value;

  }

  public void run() {

  //...

  }

  }

  对于4,如果线程进入,则线程在该类中所有操作不能进行,包括静态变量和静态方法,实际上,对于含有静态方法和静态变量的代码块的同步,我们通常用4来加锁。

  以上4种之间的关系:

  锁是和对象相关联的,每个对象有一把锁,为了执行synchronized语句,线程必须能够获得synchronized语句中表达式指定的对象的锁,一个对象只有一把锁,被一个线程获得之后它就不再拥有这把锁,线程在执行完synchronized语句后,将获得锁交还给对象。

  在方法前面加上synchronized修饰符即可以将一个方法声明为同步化方法。同步化方法在执行之前获得一个锁。如果这是一个类方法,那么获得的锁是和声明方法的类相关的Class类对象的锁。如果这是一个实例方法,那么此锁是this对象的锁。synchronzied块后面跟类的具体详细例子:

  public class DB2_JDBCFactory {

  private static DB2_JDBCFactory instance = null;

  public static final ThreadLocal threadLocal = new ThreadLocal();

  private DB2_JDBCFactory() {

  }

  public static DB2_JDBCFactory getInstance() {

  if(instance == null) {

  synchronized(DB2_JDBCFactory.class) { //synchronized后面跟一个类

  instance = new DB2_JDBCFactory();

  }

  }

  return instance;

  }

  public Connection getConnection_JNDI_localhost(){

  Connection c = (Connection) threadLocal.get();

  try {

  if (c == null || c.isClosed()) {

  InitialContext ctx = new InitialContext();

  DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/localhost");

  c = ds.getConnection();

  threadLocal.set(c);

  }

  } catch (Exception ex) {

  System.err.println("getConnection_JNDI Initial failed. " + ex);

  return null;

  }

  return c;

  }

  } 外面的对象访问这个类的 需要通过调用它的getInstance()

发表评论

评论列表