搞懂java中的synchronized关键字

1、synchronized关键字的作用域有二种:­

  1) 是某个对象实例内,synchronized aMethod(){}可以防止多个线程同时访问这个对象的synchronized方法(如果一个对象有多个synchronized方法,只要一个线程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法)。这时,不同的对象实例的 synchronized方法是不相干扰的。也就是说,其它线程照样可以同时访问相同类的另一个对象实例中的synchronized方法;­

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

  2、除了方法前用synchronized关键字,synchronized关键字还可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。­

   用法是: synchronized(this){/*区块*/},它的作用域是当前对象;­

  3、synchronized关键字是不能继承的,也就是说,基类的方法synchronized f(){} 在继承类中并不自动是synchronized f(){},而是变成了f(){}。继承类需要你显式的指定它的某个方法为synchronized方法;­

  4、疑问:­

   我知道了有static区块(其中的加载时机好像也不清楚,需要学习一下,原来看Thinking in Java好像是说: static区块加载的时机是类的一个对象实例创建或类的一个static方法被访问,但是我今天早上看了iteye.com上面的一个关于 “<static块到底什么时候执行?­

   -eway -JavaEye技术社区>”的文章后又有点迷糊了:),也许,需要认真学习一下JVM的内在机制才是理解这类问题最根本的途径),也有 synchronized区块,那么,有synchronized static 区块吗?意思是问:有没有一个类作用域内的synchronized区块?­

  今天,写了下面这个例子验证了上面有没有一个类范围的synchronized 或 synchronized static 块,结论是没有这样的块。也就是,对整个类范围的某块资源实行synchronized,唯一的方法是用:synchronized static方法,像这样:synchronized static void ff()­

  {/*your code here*/} (littlebat后注:2007.2.13,在朋友V.C的帮助下,终于知道在类的一个方法中,可以存在整个类范围内的synchronized区块,像这样:    synchronized (TestSynchronized.class) {/*some code*/},详情见后 )­

  全部的例子如下,如果我的例子和想法有任何不当的地方,还希望看见的朋友指点一下。谢谢。­

  例程: TestSynchronized.java­

public class TestSynchronized {­

 ­

  static{­

    System.out.println("Step 1: a static block in class scope.");­

  }­

  static void f(){­

    System.out.println("Step 2: a static method f() in class scope.");­

  }­

  synchronized static void ff(){ //The only way of synchronized a part in class scope.­

    System.out.println("Step 3: a synchronized static method ff() in class scope.");­

  }­

  /*//No any synchronized block in class scope!­

  synchronized {­

    System.out.println("A synchronized block in class scope.");­

  }­

  */­

  /*//No any synchronized static block in class scope!­

  synchronized static {­

    System.out.println("A synchronized static block in class scope.");­

  }­

  */­

  ­

  void fff(){­

    synchronized(this){­

      System.out.println("Step 4: a synchronized block in method fff() in object scope.");­

    }­

  }­

  ­

  synchronized void ffff(){­

    System.out.println("Step 5: a synchronized method ffff() in object scope.");­

  }­

  ­

  public static void main(String[] args) {­

    TestSynchronized.f();­

    TestSynchronized.ff();­

    (new TestSynchronized()).fff();­

    (new TestSynchronized()).ffff();­

 

    }­

}

­

  运行结果:­

Step 1: a static block in class scope.­

Step 2: a static method f() in class scope.­

Step 3: a synchronized static method ff() in class scope.­

Step 4: a synchronized block in method fff() in object scope.­

Step 5: a synchronized method ffff() in object scope.­

The format below can implement synchronizing in Class scope:­

synchronized (TestSynchronized.Class) {­

Yes, I can get synchronized block in a method in class scope­

(Note: TestSynchronized.class isn't TestSynchronized.Class):­

void fffff(){­

    synchronized (TestSynchronized.class) {­

      System.out.println("Step 6: a synchronized block in method fffff() in class scope.");­

    }­

  }

­

  ------------------------------------------------ ­

  对synchronized(this)的一些理解 :­

  ------------------------------------------------ ­

  synchronized 关键字,它包括两种用法:synchronized 方法和 synchronized 块。­

  1. synchronized 方法­

  通过在方法声明中加入 synchronized关键字来声明 synchronized 方法。如:­

  public synchronized void accessVal(int newVal);­

  synchronized 方法控制对类成员变量的访问:每个类实例对应一把锁,每个 synchronized 方法都必须获得调用该方法的类实例的锁方能执行,­

  否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。­

  这种机制确保了同一时刻对于每一个类实例,其所有声明为 synchronized 的成员函数中至多只有一个处于可执行状态(因为至多只有一个能够­

  获得该类实例对应的锁),从而有效避免了类成员变量的访问冲突(只要所有可能访问类成员变量的方法均被声明为 synchronized)。­

  在 Java 中,不光是类实例,每一个类也对应一把锁,这样我们也可将类的静态成员函数声明为 synchronized ,以控制其对类的静态成员变量的­

  访问。­

  synchronized 方法的缺陷:若将一个大的方法声明为synchronized 将会大大影响效率,典型地,若将线程类的方法 run() 声明为­

  synchronized ,由于在线程的整个生命期内它一直在运行,因此将导致它对本类任何 synchronized 方法的调用都永远不会成功。当然我们可以­

  通过将访问类成员变量的代码放到专门的方法中,将其声明为 synchronized ,并在主方法中调用来解决这一问题,但是 Java 为我们提供了更好­

  的解决办法,那就是 synchronized 块。­

  2. synchronized 块­

  通过 synchronized关键字来声明synchronized 块。语法如下:­

  synchronized(syncObject) {­

  //允许访问控制的代码­

  }­

  synchronized 块是这样一个代码块,其中的代码必须获得对象 syncObject (如前所述,可以是类实例或类)的锁方能执行,具体机制同前所述。­

  由于可以针对任意代码块,且可任意指定上锁的对象,故灵活性较高。­

  一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。­

   另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。­

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

   synchronized(this)同步代码块。­

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

   synchronized(this)同步代码块的访问将被阻塞。­

  四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,­

   它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。­

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

  举例说明:­

  一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。­

   另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。­

package ths;­

public class Thread1 implements Runnable {­

public void run() {­

synchronized(this) {­

for (int i = 0; i < 5; i++) {­

System.out.println(Thread.currentThread().getName() + " synchronized loop " + i);­

public static void main(String[] args) {­

Thread1 t1 = new Thread1();­

Thread ta = new Thread(t1, "A");­

Thread tb = new Thread(t1, "B");­

ta.start();­

tb.start();­

}

­

  结果:­

A synchronized loop 0­

A synchronized loop 1­

A synchronized loop 2­

A synchronized loop 3­

A synchronized loop 4­

B synchronized loop 0­

B synchronized loop 1­

B synchronized loop 2­

B synchronized loop 3­

B synchronized loop 4

­

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

   synchronized(this)同步代码块。­

package ths;­

public class Thread2 {­

public void m4t1() {­

synchronized(this) {­

int i = 5;­

while( i-- > 0) {­

System.out.println(Thread.currentThread().getName() + " : " + i);­

try {­

Thread.sleep(500);­

} catch (InterruptedException ie) {­

public void m4t2() {­

int i = 5;­

while( i-- > 0) {­

System.out.println(Thread.currentThread().getName() + " : " + i);­

try {­

Thread.sleep(500);­

} catch (InterruptedException ie) {­

public static void main(String[] args) {­

final Thread2 myt2 = new Thread2();­

Thread t1 = new Thread(­

new Runnable() {­

public void run() {­

myt2.m4t1();­

}, "t1"­

);­

Thread t2 = new Thread(­

new Runnable() {­

public void run() {­

myt2.m4t2();­

}, "t2"­

);­

t1.start();­

t2.start();­

 

­

  结果:­

  t1 : 4­

  t2 : 4­

  t1 : 3­

  t2 : 3­

  t1 : 2­

  t2 : 2­

  t1 : 1­

  t2 : 1­

  t1 : 0­

  t2 : 0­

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

   synchronized(this)同步代码块的访问将被阻塞。­

­

  //修改Thread2.m4t2()方法:­

public void m4t2() {­

synchronized(this) {­

int i = 5;­

while( i-- > 0) {­

System.out.println(Thread.currentThread().getName() + " : " + i);­

try {­

Thread.sleep(500);­

} catch (InterruptedException ie) {­

 

­

  结果:­

  t1 : 4­

  t1 : 3­

  t1 : 2­

  t1 : 1­

  t1 : 0­

  t2 : 4­

  t2 : 3­

  t2 : 2­

  t2 : 1­

  t2 : 0­

  四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,­

   它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。­

  //修改Thread2.m4t2()方法如下:­

public synchronized void m4t2() {­

int i = 5;­

while( i-- > 0) {­

System.out.println(Thread.currentThread().getName() + " : " + i);­

try {­

Thread.sleep(500);­

} catch (InterruptedException ie) {­

}

­

 

 

­

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
synchronized 关键字Java 的一个关键字,用于实现并发编程的同步。它可以用于方法、代码块和静态方法上。 1. 用法一:修饰实例方法 当一个线程访问一个对象的 synchronized 实例方法时,其他线程不能访问该对象的其他 synchronized 实例方法,但可以访问该对象的非 synchronized 实例方法。这种方式的锁是当前实例对象。 示例代码: ```java public synchronized void syncMethod() { // synchronized 代码块 } ``` 2. 用法二:修饰代码块 synchronized 代码块可以用来同步访问共享资源,它必须接收一个对象作为参数,该对象被称为锁对象。当线程进入 synchronized 代码块时,它必须获得锁对象的锁,其他线程在此时无法获得锁对象的锁,只有等待锁被释放。 示例代码: ```java public void syncBlock() { synchronized(this) { // synchronized 代码块 } } ``` 3. 用法三:修饰静态方法 当一个线程访问一个类的 synchronized 静态方法时,其他线程不能访问该类的其他 synchronized 静态方法,但可以访问该类的非 synchronized 静态方法。这种方式的锁是当前类的 Class 对象。 示例代码: ```java public static synchronized void syncStaticMethod() { // synchronized 代码块 } ``` 需要注意的是,使用 synchronized 关键字会降低程序的性能,因为当一个线程获得锁时,其他线程必须等待该线程释放锁才能继续执行,这会增加线程的上下文切换和调度开销。因此,在进行并发编程时,应该尽量避免使用 synchronized 关键字,而是使用更高级别的同步机制,如 Lock、Semaphore、CountDownLatch 等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值