Java synchronized详解

来源:互联网 发布:宏观经济信息数据库 编辑:程序博客网 时间:2024/06/13 22:31

Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。

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

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

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

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

代码所示:

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

public class Thread1 implements Runnable{/** * @param args */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();}public void run() {    synchronized (this) {        for (int i = 0; i < 5; i++) {            System.out.println(Thread.currentThread().getName() + " synchronized loop " + i);        }    }}  }

结果:

 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)同步代码块。

 public class Thread2 {protected void m4t1() {    synchronized (this) {        int i = 5;        while (i-- > 0) {            System.out.println(Thread.currentThread().getName() + ":" + i);            try {                Thread.sleep(500);            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }       }protected void m4t2() {    int i = 5;    while (i-- > 0) {        System.out.println(Thread.currentThread().getName() + ":" + i);        try {            Thread.sleep(1000);        } catch (InterruptedException e) {            e.printStackTrace();        }    }       }/** * @param args */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

对其它对象锁同样适用:

public class Thread3 {  class Inner {       private void m4t1() {            int i = 5;            while(i-- > 0) {                 System.out.println(Thread.currentThread().getName() + " : Inner.m4t1()=" + i);                 try {                      Thread.sleep(500);                 } catch(InterruptedException ie) {                 }            }       }       private void m4t2() {            int i = 5;            while(i-- > 0) {                 System.out.println(Thread.currentThread().getName() + " : Inner.m4t2()=" + i);                 try {                      Thread.sleep(500);                 } catch(InterruptedException ie) {                 }            }       }  }  private void m4t1(Inner inner) {       synchronized(inner) { //使用对象锁       inner.m4t1();  }  private void m4t2(Inner inner) {       inner.m4t2();  }  public static void main(String[] args) {       final Thread3 myt3 = new Thread3();       final Inner inner = myt3.new Inner();       Thread t1 = new Thread( new Runnable() {public void run() { myt3.m4t1(inner);} }, "t1");  Thread t2 = new Thread( new Runnable() {public void run() { myt3.m4t2(inner);} }, "t2");  t1.start();  t2.start();  } }

结果:

尽管线程t1获得了对Inner的对象锁,但由于线程t2访问的是同一个Inner中的非同步部分。所以两个线程互不干扰。

 t1 : Inner.m4t1()=4   t2 : Inner.m4t2()=4   t1 : Inner.m4t1()=3   t2 : Inner.m4t2()=3   t1 : Inner.m4t1()=2   t2 : Inner.m4t2()=2   t1 : Inner.m4t1()=1   t2 : Inner.m4t2()=1   t1 : Inner.m4t1()=0   t2 : Inner.m4t2()=0

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

  1. synchronized 方法:通过在方法声明中加入 synchronized关键字来声明 synchronized 方法。如:
    public synchronized void accessVal(int newVal);

  2. synchronized 块:通过 synchronized关键字来声明synchronized 块。语法如下:
    synchronized(syncObject) {
    //允许访问控制的代码
    }

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

程必须等待当前线程执行完这个代码块以后才能执行该代码块。
二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized

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

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

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

synchronized的一个简单例子

public class TextThread {/** * @param args */public static void main(String[] args) {    TxtThread thread = new TxtThread();    new Thread(thread).start();    new Thread(thread).start();    new Thread(thread).start();    new Thread(thread).start();}    }public class TxtThread implements Runnable {int num = 100;String str = new String();public void run() {    synchronized (str) {        while (num > 0) {            try {                Thread.sleep(1);            } catch (InterruptedException e) {                e.getMessage();            }            System.out.println(Thread.currentThread().getName() + "this is" + num--);        }    }}  }

总的说来,synchronized关键字可以作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块。如果再细的分类,

synchronized可作用于instance变量、object reference(对象引用)、static函数和class literals(类名称字面常量)身上。

还有一些技巧可以让我们对共享资源的同步访问更加安全:

1. 定义private 的instance变量+它的 get方法,而不要定义public/protected的instance变量。如果将变量定义为public,对象在外界可以

绕过同步方法的控制而直接取得它,并改动它。这也是JavaBean的标准实现方式之一。

2. 如果instance变量是一个对象,如数组或ArrayList什么的,那上述方法仍然不安全,因为当外界对象通过get方法拿到这个instance对象

的引用后,又将其指向另一个对象,那么这个private变量也就变了,岂不是很危险。 这个时候就需要将get方法也加上synchronized同步,并

且,只返回这个private对象的clone()――这样,调用端得到的就是对象副本的引用了。

0 0