synchronized翻译为中文的意思是同步的,它是Java中处理线程安全问题常用的关键字,也有人称其为同步锁。
(1)synchronized锁住的是对象而非代码,实际保护的是同一个对象的方法调用,确保同时只能有一个线程执行。
(2)再具体来说,synchronized锁住的对象有一个锁和一个等待队列,锁只能被一个线程持有,其他试图获得同样锁的线程需要等待,执行synchronized实例方法的过程大概如下:
①尝试获得锁,如果能够获得锁,继续下一步,否则加入等待队列,线程的状态会变为阻塞(BLOCKED)并等待唤醒;
②执行方法体代码;
③释放锁,如果等待队列上有等待的线程,从中取一个并唤醒,如果有多个等待的线程,唤醒哪一个是不一定的,不保证公平性。
(1)IService接口
public interface IService {
void serviceMethodA(String param);
void serviceMethodB(String param);
}
(2)线程A
public class ThreadA extends Thread {
private IService mService;
private String mParam;
public ThreadA(IService service, String param) {
super();
this.mService = service;
this.mParam = param;
}
@Override
public void run() {
super.run();
mService.serviceMethodA(mParam);
}
}
(3)线程B
public class ThreadB extends Thread {
private IService mService;
private String mParam;
public ThreadB(IService service, String param) {
super();
this.mService = service;
this.mParam = param;
}
@Override
public void run() {
super.run();
mService.serviceMethodB(mParam);
}
}
(1)ThisService
public class ThisService implements IService {
@Override
public void serviceMethodA(String param) {
try {
synchronized (this) {
System.out.println("A begin time=" + System.currentTimeMillis());
Thread.sleep(2000);
System.out.println("A end time=" + System.currentTimeMillis());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void serviceMethodB(String param) {
synchronized (this) {
System.out.println("B begin time=" + System.currentTimeMillis());
System.out.println("B end time=" + System.currentTimeMillis());
}
}
}
(2)执行代码:验证synchronized锁住的代码块间的同步性
// 执行验证synchronized锁住的代码块间的同步性
public void textSynchronizeThis() {
ThisService service = new ThisService();
ThreadA threadA = new ThreadA(service, "");
threadA.setName("a");
threadA.start();
ThreadB threadB = new ThreadB(service, "");
threadB.setName("b");
threadB.start();
}
(3)结果
/***
* 结果:ThreadA和ThreadB同步执行了
* 2019-08-25 14:45:56.400 15246-15268/com.seniorlibs.thread I/System.out: B begin time=1566715556400
* 2019-08-25 14:45:56.400 15246-15268/com.seniorlibs.thread I/System.out: B end time=1566715556400
* 2019-08-25 14:45:56.400 15246-15267/com.seniorlibs.thread I/System.out: A begin time=1566715556400
* 2019-08-25 14:45:58.402 15246-15267/com.seniorlibs.thread I/System.out: A end time=1566715558402
*/
(4)结论
当一个线程访问ThisService的一个synchronized (this)同步代码块时,其它线程对同一个ThisService中其它的synchronized (this)同步代码块的访问将是堵塞,这说明synchronized (this)使用的对象监视器是同一个。
(1)LocalThisService
public class LocalThisService implements IService{
/**
* 结果:ThreadA和ThreadB异步执行了
* 2019-08-25 14:49:51.328 15628-15649/com.seniorlibs.thread I/System.out: synchronized thread name:b-->i=1
* 2019-08-25 14:49:51.329 15628-15648/com.seniorlibs.thread I/System.out: run----serviceMethodA
* 2019-08-25 14:49:52.344 15628-15649/com.seniorlibs.thread I/System.out: synchronized thread name:b-->i=2
* 2019-08-25 14:49:53.345 15628-15649/com.seniorlibs.thread I/System.out: synchronized thread name:b-->i=3
* 2019-08-25 14:49:54.347 15628-15649/com.seniorlibs.thread I/System.out: synchronized thread name:b-->i=4
* 2019-08-25 14:49:55.348 15628-15649/com.seniorlibs.thread I/System.out: synchronized thread name:b-->i=5
* @param param
*/
// @Override
// public void serviceMethodA(String param) {
// System.out.println("run----serviceMethodA");
// }
/**
* 加上同步synchronized
* 结果:ThreadA和ThreadB同步执行了
* 2019-08-25 14:51:19.941 15753-15773/com.seniorlibs.thread I/System.out: synchronized thread name:b-->i=1
* 2019-08-25 14:51:20.948 15753-15773/com.seniorlibs.thread I/System.out: synchronized thread name:b-->i=2
* 2019-08-25 14:51:21.950 15753-15773/com.seniorlibs.thread I/System.out: synchronized thread name:b-->i=3
* 2019-08-25 14:51:22.951 15753-15773/com.seniorlibs.thread I/System.out: synchronized thread name:b-->i=4
* 2019-08-25 14:51:23.953 15753-15773/com.seniorlibs.thread I/System.out: synchronized thread name:b-->i=5
* 2019-08-25 14:51:24.953 15753-15772/com.seniorlibs.thread I/System.out: run----serviceMethodA
* @param param
*/
@Override
public synchronized void serviceMethodA(String param){
System.out.println("run----serviceMethodA");
}
@Override
public void serviceMethodB(String param) {
synchronized (this) {
try {
for (int i = 1; i <= 5; i++) {
System.out.println("synchronized thread name:" + Thread.currentThread().getName() + "-->i=" + i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
(2)执行代码:验证synchronized锁住的代码块间的同步性
public void textSynchronizeLocalThis() {
LocalThisService service = new LocalThisService();
ThreadA threadA = new ThreadA(service, "");
threadA.setName("a");
threadA.start();
ThreadB threadB = new ThreadB(service, "");
threadB.setName("b");
threadB.start();
}
(3)结果,在(1)中
(4)结论
多个线程调用同一个对象中的“不同名称的synchronized方法”和“synchronized(this)代码块”时,是同步的。因为synchronized方法锁住的是当前对象,所以synchronized(this)代码块也是锁定当前对象。
(1)ObjectService
public class ObjectService implements IService {
private final StringBuilder lock = new StringBuilder();
/**
* 结果:ThreadA和ThreadB异步执行了
* System.out: thread name=b 进入代码快:1566717388490
* System.out: thread name=a 进入代码快:1566717388492
* System.out: thread name=b 进入代码快:1566717391491 入参:ThreadB
* System.out: thread name=a 进入代码快:1566717391494 入参:ThreadA
* @param param
*/
// @Override
// public void serviceMethodA(String param) {
// try {
// StringBuilder lock = new StringBuilder();
// synchronized (lock) {
// String threadName = Thread.currentThread().getName();
// System.out.println("thread name=" + threadName + " 进入代码快:" + System.currentTimeMillis());
// Thread.sleep(3000);
// System.out.println("thread name=" + threadName + " 进入代码快:" + System.currentTimeMillis() + " 入参:" + param);
// }
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
/**
* 结果:ThreadA和ThreadB同步执行了
* System.out: thread name=a 进入代码快:1566717191405
* System.out: thread name=a 进入代码快:1566717194406 入参:ThreadA
* System.out: thread name=b 进入代码快:1566717194407
* System.out: thread name=b 进入代码快:1566717197407 入参:ThreadB
* @param param
*/
@Override
public void serviceMethodA(String param) {
try {
synchronized (lock) {
String threadName = Thread.currentThread().getName();
System.out.println("thread name=" + threadName + " 进入代码快:" + System.currentTimeMillis());
Thread.sleep(3000);
System.out.println("thread name=" + threadName + " 进入代码快:" + System.currentTimeMillis() + " 入参:" + param);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void serviceMethodB(String param) {
serviceMethodA(param);
}
}
(2)附加:修改ObjectService实现synchronized(任意对象)与synchronized同步方法共用
public class ObjectService implements IService {
private final StringBuilder lock = new StringBuilder();
@Override
public void serviceMethodA(String param) {
try {
synchronized (lock) {
String threadName = Thread.currentThread().getName();
System.out.println("thread name=" + threadName + " 进入代码快:" + System.currentTimeMillis());
Thread.sleep(3000);
System.out.println("thread name=" + threadName + " 进入代码快:" + System.currentTimeMillis() + " 入参:" + param);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 结果:ThreadA和ThreadB异步执行了
* System.out: thread name=b 进入代码快:1566717724148
* System.out: thread name=a 进入代码快:1566717724151
* System.out: thread name=b 进入代码快:1566717727149 入参:ThreadB
* System.out: thread name=a 进入代码快:1566717727152 入参:ThreadA
* @param param
*/
@Override
public synchronized void serviceMethodB(String param) {
try {
System.out.println("thread name=" + Thread.currentThread().getName() + " 进入代码快:" + System.currentTimeMillis());
Thread.sleep(3000);
System.out.println("thread name=" + Thread.currentThread().getName() + " 进入代码快:" + System.currentTimeMillis() + " 入参:" + param);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
(3)执行代码:验证synchronized(任意对象)代码块是锁定此对象
public void textSynchronizeObject() {
ObjectService service = new ObjectService();
ThreadA threadA = new ThreadA(service, "ThreadA");
threadA.setName("a");
threadA.start();
ThreadB threadB = new ThreadB(service, "ThreadB");
threadB.setName("b");
threadB.start();
}
(4)结果,在(1)中
(5)结论
使用synchronized(任意对象)进行同步操作,对象必须是同一个对象;如果不是同一个对象,运行就是异步执行了。
多个线程调用同一个对象中的“不同名称的synchronized方法”和“synchronized(任意对象)代码块”时,是异步的。因为synchronized方法锁住的是当前对象,所以synchronized(任意对象)代码块是锁定此对象。
(1)StaticService
public class StaticService implements IService {
@Override
public void serviceMethodA(String param) {
methodA(param);
}
// private synchronized static void methodA(String param) {
// try {
// System.out.println("A begin time=" + System.currentTimeMillis());
// Thread.sleep(3000);
// System.out.println("A end time=" + System.currentTimeMillis());
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
// private synchronized void methodA(String param) {
// try {
// System.out.println("A begin time=" + System.currentTimeMillis());
// Thread.sleep(3000);
// System.out.println("A end time=" + System.currentTimeMillis());
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
private void methodA(String param) {
try {
synchronized (StaticService.class) {
System.out.println("A begin time=" + System.currentTimeMillis());
Thread.sleep(3000);
System.out.println("A end time=" + System.currentTimeMillis());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void serviceMethodB(String param) {
methodB(param);
}
// private synchronized static void methodB(String param) {
// try {
// System.out.println("B begin time=" + System.currentTimeMillis());
// Thread.sleep(1000);
// System.out.println("B end time=" + System.currentTimeMillis());
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
// private synchronized void methodB(String param) {
// try {
// System.out.println("B begin time=" + System.currentTimeMillis());
// Thread.sleep(1000);
// System.out.println("B end time=" + System.currentTimeMillis());
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
private void methodB(String param) {
try {
synchronized (StaticService.class) {
System.out.println("B begin time=" + System.currentTimeMillis());
Thread.sleep(1000);
System.out.println("B end time=" + System.currentTimeMillis());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 结果:synchronized static + 一个/多个StaticService对象 --->ThreadA和ThreadB同步执行了
* 2019-08-25 15:39:30.711 18410-18429/com.seniorlibs.thread I/System.out: B begin time=1566718770711
* 2019-08-25 15:39:31.719 18410-18429/com.seniorlibs.thread I/System.out: B end time=1566718771719
* 2019-08-25 15:39:31.719 18410-18428/com.seniorlibs.thread I/System.out: A begin time=1566718771719
* 2019-08-25 15:39:34.721 18410-18428/com.seniorlibs.thread I/System.out: A end time=1566718774721
*
* 结果:synchronized (StaticService.class) + 一个/多个StaticService对象 --->ThreadA和ThreadB同步执行了
* 2019-08-25 15:49:15.626 18996-19017/com.seniorlibs.thread I/System.out: B begin time=1566719355626
* 2019-08-25 15:49:16.630 18996-19017/com.seniorlibs.thread I/System.out: B end time=1566719356630
* 2019-08-25 15:49:16.631 18996-19016/com.seniorlibs.thread I/System.out: A begin time=1566719356631
* 2019-08-25 15:49:19.632 18996-19016/com.seniorlibs.thread I/System.out: A end time=1566719359632
*
* 结果:synchronized + 一个StaticService对象 --->ThreadA和ThreadB同步执行了
* 2019-08-25 15:39:30.711 18410-18429/com.seniorlibs.thread I/System.out: B begin time=1566718770711
* 2019-08-25 15:39:31.719 18410-18429/com.seniorlibs.thread I/System.out: B end time=1566718771719
* 2019-08-25 15:39:31.719 18410-18428/com.seniorlibs.thread I/System.out: A begin time=1566718771719
* 2019-08-25 15:39:34.721 18410-18428/com.seniorlibs.thread I/System.out: A end time=1566718774721
*
* 结果:synchronized + 多个StaticService对象 --->ThreadA和ThreadB异步执行了
* 2019-08-25 15:42:16.522 18724-18743/com.seniorlibs.thread I/System.out: B begin time=1566718936522
* 2019-08-25 15:42:16.528 18724-18742/com.seniorlibs.thread I/System.out: A begin time=1566718936527
* 2019-08-25 15:42:17.525 18724-18743/com.seniorlibs.thread I/System.out: B end time=1566718937525
* 2019-08-25 15:42:19.528 18724-18742/com.seniorlibs.thread I/System.out: A end time=1566718939528
*/
}
(2)执行代码:验证静态synchronized方法是对当前对应的*.Class进行持锁
public void textSynchronizeLocalStatic() {
StaticService service = new StaticService();
ThreadA threadA = new ThreadA(service, "");
threadA.setName("a");
threadA.start();
StaticService service2 = new StaticService();
ThreadB threadB = new ThreadB(service2, "");
threadB.setName("b");
threadB.start();
}
(3)结果,在(1)中
(4)结论
同步synchronized(*.class)代码块的作用其实和synchronized static方法作用一样。Class锁对类的所有对象实例起作用。
ynchronized(this)、synchronized(class)与synchronized(Object)的区别
Counter是一个简单的计数器类,incr方法和getCount方法都加了synchronized修饰。加了synchronized后,方法内的代码就变成了原子操作,当多个线程并发更新同一个Counter对象的时候,也不会出现问题。
(1)synchronized方法
public class Counter {
private int count;
public synchronized void incr(){
count ++;
}
public synchronized int getCount() {
return count;
}
}
(2)synchronized(this)代码块
public class Counter {
private int count;
public void incr(){
synchronized(this){
count ++;
}
}
public int getCount() {
synchronized(this){
return count;
}
}
}
(3)synchronized static方法(注意:count是static)
public class StaticCounter {
private static int count = 0;
public static synchronized void incr() {
count++;
}
public static synchronized int getCount() {
return count;
}
}
(4)synchronized(.class)方法(注意:count是static)
public class StaticCounter {
private static int count = 0;
public static void incr() {
synchronized(StaticCounter.class){
count++;
}
}
public static int getCount() {
synchronized(StaticCounter.class){
return count;
}
}
}
(5)synchronized(任意对象),任意对象都有一个锁和等待队列。或者说,任何对象都可以作为锁对象
public class Counter {
private int count;
private Object lock = new Object();
public void incr(){
synchronized(lock){
count ++;
}
}
public int getCount() {
synchronized(lock){
return count;
}
}
}
Java编程的逻辑----理解synchronized