synchronized详解:
被它修饰的代码块或方法,能够保证同一时间只能有一个线程执行该段代码.
一、当两个并发线程访问同一个对象object的synchronized(this)同步代码块/同步方法的时候,另一个线程仍可以访问该object的非同步代码块/非同步方法。
package com.syn; public class synTest { public static void main(String[] args) { final SynObj so = new SynObj(); Thread t1 = new Thread(new Runnable() { public void run() { so.methodOne(); } }); Thread t2 = new Thread(new Runnable(){ public void run(){ so.methodTwo(); } }); t1.start(); t2.start(); } } class SynObj extends Thread{ public synchronized void methodOne(){ int count = 5; while(count > 0){ System.out.println(Thread.currentThread().getName() + " " + count--); } } public void methodTwo(){ int count = 5; while(count > 0){ System.out.println(Thread.currentThread().getName() + " " + count--); } } }
Thread-1 5 Thread-1 4 Thread-2 5 Thread-1 3 Thread-2 4 Thread-1 2 Thread-2 3 Thread-1 1 Thread-2 2 Thread-2 1
如果我们将上面代码的methodTwo加上synchronized,或者声明为同步代码块:
public synchronized void methodTwo(){ int count = 5; while(count > 0){ System.out.println(Thread.currentThread().getName() + " " + count--); } }
public void methodTwo(){ synchronized(this){ int count = 5; while(count > 0){ System.out.println(Thread.currentThread().getName() + " " + count--); } } }
Thread-1 5 Thread-1 4 Thread-1 3 Thread-1 2 Thread-1 1 Thread-2 5 Thread-2 4 Thread-2 3 Thread-2 2 Thread-2 1
synchronized 方法和 synchronized 块:
1.synchronized 方法
每个类实例都有一个锁,每个synchronized方法只有在获得调用该方法的实例的锁之后才能执行,否则该线程阻塞,方法一旦执行,就独占该锁,直至方法退出。这种机制保证了同一个时刻对于每一个类实例,在所有声明为synchronized的成员函数中至多只有一个处于执行状态,(因为至多只有一个能够获得该类实例对应的锁),从而有效避免了类成员变量的访问冲突(只要所有可能访问类成员变量的方法均被声明为 synchronized)。
在 Java 中,不光是类实例,每一个类也对应一把锁,这样我们也可将类的静态成员函数声明为 synchronized ,以控制其对类的静态成员变量的访问。
synchronized 方法的缺陷:若将一个大的方法声明为synchronized 将会大大影响效率,典型地,若将线程类的方法 run() 声明为synchronized ,由于在线程的整个生命期内它一直在运行,因此将导致它对本类任何 synchronized 方法的调用都永远不会成功。
2.synchronized 块:
通过 synchronized关键字来声明synchronized 块。语法如下:
synchronized(syncObject) {
//允许访问控制的代码
}
synchronized 块是这样一个代码块,其中的代码必须获得对象 syncObject (如前所述,可以是类实例或类)的锁方能执行。
被它修饰的代码块或方法,能够保证同一时间只能有一个线程执行该段代码.
一、当两个并发线程访问同一个对象object的synchronized(this)同步代码块/同步方法的时候,另一个线程仍可以访问该object的非同步代码块/非同步方法。
package com.syn; public class synTest { public static void main(String[] args) { final SynObj so = new SynObj(); Thread t1 = new Thread(new Runnable() { public void run() { so.methodOne(); } }); Thread t2 = new Thread(new Runnable(){ public void run(){ so.methodTwo(); } }); t1.start(); t2.start(); } } class SynObj extends Thread{ public synchronized void methodOne(){ int count = 5; while(count > 0){ System.out.println(Thread.currentThread().getName() + " " + count--); } } public void methodTwo(){ int count = 5; while(count > 0){ System.out.println(Thread.currentThread().getName() + " " + count--); } } }
Thread-1 5 Thread-1 4 Thread-2 5 Thread-1 3 Thread-2 4 Thread-1 2 Thread-2 3 Thread-1 1 Thread-2 2 Thread-2 1
如果我们将上面代码的methodTwo加上synchronized,或者声明为同步代码块:
public synchronized void methodTwo(){ int count = 5; while(count > 0){ System.out.println(Thread.currentThread().getName() + " " + count--); } }
public void methodTwo(){ synchronized(this){ int count = 5; while(count > 0){ System.out.println(Thread.currentThread().getName() + " " + count--); } } }
Thread-1 5 Thread-1 4 Thread-1 3 Thread-1 2 Thread-1 1 Thread-2 5 Thread-2 4 Thread-2 3 Thread-2 2 Thread-2 1
synchronized 方法和 synchronized 块:
1.synchronized 方法
每个类实例都有一个锁,每个synchronized方法只有在获得调用该方法的实例的锁之后才能执行,否则该线程阻塞,方法一旦执行,就独占该锁,直至方法退出。这种机制保证了同一个时刻对于每一个类实例,在所有声明为synchronized的成员函数中至多只有一个处于执行状态,(因为至多只有一个能够获得该类实例对应的锁),从而有效避免了类成员变量的访问冲突(只要所有可能访问类成员变量的方法均被声明为 synchronized)。
在 Java 中,不光是类实例,每一个类也对应一把锁,这样我们也可将类的静态成员函数声明为 synchronized ,以控制其对类的静态成员变量的访问。
synchronized 方法的缺陷:若将一个大的方法声明为synchronized 将会大大影响效率,典型地,若将线程类的方法 run() 声明为synchronized ,由于在线程的整个生命期内它一直在运行,因此将导致它对本类任何 synchronized 方法的调用都永远不会成功。
2.synchronized 块:
通过 synchronized关键字来声明synchronized 块。语法如下:
synchronized(syncObject) {
//允许访问控制的代码
}
synchronized 块是这样一个代码块,其中的代码必须获得对象 syncObject (如前所述,可以是类实例或类)的锁方能执行。