前言
在介绍synchronized方法和synchronized代码块前,先对监视器(Monitor)做一个说明,在java虚拟机中,每个对象(object和class)通过某种逻辑关联监视器,每个监视器和一个对象引用相关联,为了实现监视器的互斥功能,每个对象都关联着一把锁一旦方法或者代码块被synchronized修饰,那么这个部分就放入了监视器的监视区域,确保一次只能有一个线程执行该部分的代码,线程在获取锁之前不允许执行该部分的代码。
想详细了解此概念可以查看下面的博客:
JAVA并发:多线程编程之同步“监视器monitor”(三)
synchronized方法
synchronized方法分为两种,一种是静态synchronized方法,另一种是非静态synchronized方法。这两种的区别在于两个的对象锁不同及监视器不同。非静态synchronized方法的锁是当前实例对象。如果是同一个实例对象,那么不同线程调用同一非静态synchronized方法与调用不同非静态synchronized方法都竞争同一把锁,如果是不同实例对象,那么就会异步执行。下面以一个例子展示下同一个实例对象调用同一个非静态synchronized方法。
package thread.synchronize;
/***
* 需要同步的逻辑处理层
* @author swh
*
*/
public class SynchronizedMethondService {
synchronized public void doService() {
System.out.println(Thread.currentThread().getName()+":"+"开始执行");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":"+"执行结束");
}
synchronized public void doServiceB() {
System.out.println(Thread.currentThread().getName()+":"+"B开始执行");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":"+"B执行结束");
}
}
package thread.synchronize;
/***
* 用非静态synchronized方法的测试线程
* @author swh
*
*/
public class SynchronizedMethondThread extends Thread {
private SynchronizedMethondService service;
public SynchronizedMethondThread(SynchronizedMethondService service) {
this.service = service;
}
@Override
public void run() {
service.doService();
}
public static void main(String args[]) {
SynchronizedMethondService service = new SynchronizedMethondService();
SynchronizedMethondThread threadA = new SynchronizedMethondThread(service);
threadA.start();
SynchronizedMethondThread threadB = new SynchronizedMethondThread(service);
threadB.start();
}
}
下面的运行的结果,因为调用的通过一个实例对象的非静态synchronized方法,需要竞争同一把锁,所以会同步执行。我现在调用不同实例对象的方法看下是否会异步执行。更改的代码如下:
package thread.synchronize;
/***
* 用非synchronized方法的测试线程
* @author swh
*
*/
public class SynchronizedMethondThread extends Thread {
private SynchronizedMethondService service;
public SynchronizedMethondThread(SynchronizedMethondService service) {
this.service = service;
}
@Override
public void run() {
service.doService();
}
public static void main(String args[]) {
SynchronizedMethondService serviceA = new SynchronizedMethondService();
SynchronizedMethondThread threadA = new SynchronizedMethondThread(serviceA);
threadA.start();
SynchronizedMethondService serviceB = new SynchronizedMethondService();
SynchronizedMethondThread threadB = new SynchronizedMethondThread(serviceB);
threadB.start();
}
}
最后执行的结果如下,因为两个线程执行的方法是两个不同实例对象的,两个线程竞争的不是同一把锁,所以最后异步执行了。
上面的例子我们验证了不同线程调用同一实例对象的非静态synchronized方法和不同实例对象的步同非静态synchronized方法,下面我们再验证下不同线程调用不同非静态synchronized方法。
package thread.synchronize;
/***
* 用非synchronized方法的测试线程
* @author swh
*
*/
public class SynchronizedMethondThreadB extends Thread {
private SynchronizedMethondService service;
public SynchronizedMethondThreadB(SynchronizedMethondService service) {
this.service = service;
}
@Override
public void run() {
service.doServiceB();
}
}
package thread.synchronize;
/***
* 用非synchronized方法的测试线程
* @author swh
*
*/
public class SynchronizedMethondThread extends Thread {
private SynchronizedMethondService service;
public SynchronizedMethondThread(SynchronizedMethondService service) {
this.service = service;
}
@Override
public void run() {
service.doService();
}
public static void main(String args[]) {
SynchronizedMethondService serviceA = new SynchronizedMethondService();
SynchronizedMethondThread threadA = new SynchronizedMethondThread(serviceA);
threadA.start();
SynchronizedMethondThreadB threadB = new SynchronizedMethondThreadB(serviceA);
threadB.start();
}
}
静态synchronized方法和非静态synchronized方法方法区别在于静态synchronized方法的锁是当前类的class对象,而非静态synchronized方法的锁是当前实例对象,所有静态synchronized方法竞争的都是同一把锁,下面我们以一个简单的例子来验证下。
package thread.synchronize;
/***
* 需要同步的逻辑处理层
* @author swh
*
*/
public class SynchronizedMethondService {
synchronized public static void doService() {
System.out.println(Thread.currentThread().getName()+":"+"开始执行");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":"+"执行结束");
}
synchronized public static void doServiceB() {
System.out.println(Thread.currentThread().getName()+":"+"B开始执行");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":"+"B执行结束");
}
}
package thread.synchronize;
/***
* synchronized方法的测试线程
* @author swh
*
*/
public class SynchronizedMethondThread extends Thread {
private SynchronizedMethondService service;
public SynchronizedMethondThread(SynchronizedMethondService service) {
this.service = service;
}
@Override
public void run() {
service.doService();
}
public static void main(String args[]) {
SynchronizedMethondService serviceA = new SynchronizedMethondService();
SynchronizedMethondThread threadA = new SynchronizedMethondThread(serviceA);
threadA.start();
SynchronizedMethondService serviceB = new SynchronizedMethondService();
SynchronizedMethondThread threadB = new SynchronizedMethondThread(serviceB);
threadB.start();
}
}
运行的结果如下,是同步执行的。
synchronized代码块
同步代码块需要传递的对象(锁对象):就是锁住这个对象,表示这个对象正在为我服务,其他线程不能用(非synchronized代码块、方法除外),下面我验证调用同一个实例对象的同步方法同步代码是否会同步执行。
package thread.synchronize;
/***
* 需要同步的逻辑处理层
* @author swh
*
*/
public class SynchronizedMethondService {
synchronized public void doService() {
System.out.println(Thread.currentThread().getName()+":"+"开始执行");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":"+"执行结束");
}
synchronized public void doServiceB() {
synchronized(this){
System.out.println(Thread.currentThread().getName()+":"+"B开始执行");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":"+"B执行结束");
}
}
}
package thread.synchronize;
/***
* 用synchronize代码块的测试线程
* @author swh
*
*/
public class SynchronizedMethondThreadB extends Thread {
private SynchronizedMethondService service;
public SynchronizedMethondThreadB(SynchronizedMethondService service) {
this.service = service;
}
@Override
public void run() {
service.doServiceB();
}
}
package thread.synchronize;
/***
* synchronized方法的测试线程
* @author swh
*
*/
public class SynchronizedMethondThread extends Thread {
private SynchronizedMethondService service;
public SynchronizedMethondThread(SynchronizedMethondService service) {
this.service = service;
}
@Override
public void run() {
service.doService();
}
public static void main(String args[]) {
SynchronizedMethondService serviceA = new SynchronizedMethondService();
SynchronizedMethondThread threadA = new SynchronizedMethondThread(serviceA);
threadA.start();
SynchronizedMethondThreadB threadB = new SynchronizedMethondThreadB(serviceA);
threadB.start();
}
}