由于同一进程的多个线程共享同一片内存存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题。Java语言提供了专门的机制来解决这种冲突,有效的避免了同一个数据对象被多个线程同时访问。
需要明确的几个问题:
synchronized关键字可以作为方法的修饰符,也可以作为方法内的语句(即平时说的同步方法和同步代码块)如果再细分,其可以作用于instance(成员变量)、object reference(对象应用)、static(静态方法)和class literals(类名称字面常量)上
无论synchronized 关键字作用于方法还是对象上,他取得的锁都是对象锁
每个对象只有一个锁与之关联
实现同步需要很大的系统开销做为代价的,同步可能造成死锁,所以程序设计时应尽量避免使用无谓的同步控制
synchronized 作用域对比分析,案例代码如下:
package org.xyz.java.basic.keys;
import java.util.concurrent.TimeUnit;
/**
* synchronized 关键字讲解
* @author kevin.chen
*/
public class SynchronizedDemo {
public static void main(String[] args) {
/**
* a()和c()方法竞争同一把锁,对应Thread-0和Thread-2线程;
* b()和d()方法竞争另外一把锁,对应Thread-1和main线程
Thread-0: synchronized in a()
Thread-0: synchronized in a() for -> 0
Thread-1: synchronized in b()
Thread-1: synchronized in b() for -> 0
main: not synchronized in d()
Thread-2: not synchronized in c()
Thread-1: synchronized in b() for -> 1
Thread-0: synchronized in a() for -> 1
Thread-0: synchronized in a() for -> 2
Thread-1: synchronized in b() for -> 2
Thread-0: synchronized in a() for -> 3
Thread-1: synchronized in b() for -> 3
Thread-0: synchronized in a() for -> 4
Thread-1: synchronized in b() for -> 4
Thread-2: synchronized in c() for -> 0
main: synchronized in d() for -> 0
main: synchronized in d() for -> 1
Thread-2: synchronized in c() for -> 1
Thread-2: synchronized in c() for -> 2
main: synchronized in d() for -> 2
Thread-2: synchronized in c() for -> 3
main: synchronized in d() for -> 3
Thread-2: synchronized in c() for -> 4
main: synchronized in d() for -> 4
main thread over
*/
Foo.doRun();
}
}
/**
* synchronized 作用于方法和作用于代码块的对比
* @author kevin.chen
*/
class Foo {
/**
* synchronized 关键字修饰在类的静态方法中,此时线程调用该方法,
* 需要获取的锁对象是类锁,相当于Foo.class
*/
synchronized public static void a() {
System.out.println(Thread.currentThread().getName() + ": synchronized in a()");
for(int i = 0; i< 5; i++) {
System.out.println(Thread.currentThread().getName() + ": synchronized in a() for -> " + i);
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* synchronized 关键字修饰在类的普通方法中,此时线程调用该方法,
* 需要获取的锁对象是类实例对象锁,相当于this
*/
synchronized public void b() {
System.out.println(Thread.currentThread().getName() + ": synchronized in b()");
for(int i = 0; i< 5; i++) {
System.out.println(Thread.currentThread().getName() + ": synchronized in b() for -> " + i);
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 该方法和a()方法竞争同一把锁
*/
public void c() {
System.out.println(Thread.currentThread().getName() + ": not synchronized in c()");
synchronized (Foo.class) {
for(int i = 0; i< 5; i++) {
System.out.println(Thread.currentThread().getName() + ": synchronized in c() for -> " + i);
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
/**
* 该方法和b()方法竞争同一把锁
*/
public void d() {
System.out.println(Thread.currentThread().getName() + ": not synchronized in d()");
synchronized (this) {
for(int i = 0; i< 5; i++) {
System.out.println(Thread.currentThread().getName() + ": synchronized in d() for -> " + i);
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public static void doRun() {
Foo s = new Foo();
// 创建一个线程执行a()
new Thread() {
public void run() {
Foo.a();
}
}.start();
// 创建一个线程执行b()
new Thread() {
public void run() {
s.b();
}
}.start();
// 创建一个线程执行b()
new Thread() {
public void run() {
s.c();
}
}.start();
// 使用主线程执行c()
s.d();
System.out.println("main thread over");
}
}
详细案例参考如下代码示例:
package org.xyz.java.basic.keys;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* synchronized 关键字讲解
* @author kevin.chen
*/
public class SynchronizedDemo2 {
public static void main(String[] args) {
/**
* 线程竞争同一把锁,竞争到锁的线程进行操作,没有竞争到锁的线程阻塞
Thread-0: not synchronized in a()
Thread-1: not synchronized in b()
main: not synchronized in c()
Thread-0: synchronized in a() for -> 0
Thread-0: synchronized in a() for -> 1
Thread-0: synchronized in a() for -> 2
Thread-0: synchronized in a() for -> 3
Thread-0: synchronized in a() for -> 4
main: synchronized in c() for -> 0
main: synchronized in c() for -> 1
main: synchronized in c() for -> 2
main: synchronized in c() for -> 3
main: synchronized in c() for -> 4
Thread-1: synchronized in b() for -> 0
Thread-1: synchronized in b() for -> 1
Thread-1: synchronized in b() for -> 2
Thread-1: synchronized in b() for -> 3
Thread-1: synchronized in b() for -> 4
*/
// Sd01.doRun();
/**
* 线程竞争各自的锁,线程之间不存在竞争关系,无阻塞
Thread-0: not synchronized in a()
main: not synchronized in c()
main: synchronized in c() for -> 0
Thread-0: synchronized in a() for -> 0
Thread-1: not synchronized in b()
Thread-1: synchronized in b() for -> 0
Thread-0: synchronized in a() for -> 1
Thread-1: synchronized in b() for -> 1
main: synchronized in c() for -> 1
Thread-0: synchronized in a() for -> 2
main: synchronized in c() for -> 2
Thread-1: synchronized in b() for -> 2
main: synchronized in c() for -> 3
Thread-0: synchronized in a() for -> 3
Thread-1: synchronized in b() for -> 3
main: synchronized in c() for -> 4
Thread-0: synchronized in a() for -> 4
Thread-1: synchronized in b() for -> 4
main thread over
*/
// Sd02.doRun();
/**
* 线程竞争同一把锁,竞争到锁的线程进行操作,没有竞争到锁的线程阻塞(效果和Sd01一致,但比使用synchronized比较灵活)
Thread-0: not synchronized in a()
main: not synchronized in c()
Thread-0: synchronized in a() for -> 0
Thread-1: not synchronized in b()
Thread-0: synchronized in a() for -> 1
Thread-0: synchronized in a() for -> 2
Thread-0: synchronized in a() for -> 3
Thread-0: synchronized in a() for -> 4
main: synchronized in c() for -> 0
main: synchronized in c() for -> 1
main: synchronized in c() for -> 2
main: synchronized in c() for -> 3
main: synchronized in c() for -> 4
Thread-1: synchronized in b() for -> 0
main thread over
Thread-1: synchronized in b() for -> 1
Thread-1: synchronized in b() for -> 2
Thread-1: synchronized in b() for -> 3
Thread-1: synchronized in b() for -> 4
*/
// Sd03.doRun();
/**
* 线程竞争各自的锁,线程之间不存在竞争关系,
* 无阻塞(效果和Sd02一致,但比使用synchronized比较灵活)
Thread-0: not synchronized in a()
Thread-0: synchronized in a() for -> 0
main: not synchronized in c()
main: synchronized in c() for -> 0
Thread-1: not synchronized in b()
Thread-1: synchronized in b() for -> 0
main: synchronized in c() for -> 1
Thread-0: synchronized in a() for -> 1
Thread-1: synchronized in b() for -> 1
main: synchronized in c() for -> 2
Thread-0: synchronized in a() for -> 2
Thread-1: synchronized in b() for -> 2
main: synchronized in c() for -> 3
Thread-0: synchronized in a() for -> 3
Thread-1: synchronized in b() for -> 3
main: synchronized in c() for -> 4
Thread-1: synchronized in b() for -> 4
Thread-0: synchronized in a() for -> 4
main thread over
*/
Sd04.doRun();
}
}
/**
* 同步代码块中使用的都是this对象(任意同一对象都类似)作为对象锁,
* 所以这3个方法竞争的是同一把锁,当3个线程(含主线程)中的任意一个线程拿到锁后,其他线程都进入阻塞排队状态
* @author kevin.chen
*/
class Sd01 {
public void a() {
System.out.println(Thread.currentThread().getName() + ": not synchronized in a()");
/*
* 这里使用this,也可以这样
* Object obj = new Object();
* synchronized (obj)
*/
synchronized (this) {
for(int i = 0; i< 5; i++) {
System.out.println(Thread.currentThread().getName() + ": synchronized in a() for -> " + i);
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public void b() {
System.out.println(Thread.currentThread().getName() + ": not synchronized in b()");
/*
* 这里使用this,也可以这样
* Object obj = new Object();
* synchronized (obj)
*/
synchronized (this) {
for(int i = 0; i< 5; i++) {
System.out.println(Thread.currentThread().getName() + ": synchronized in b() for -> " + i);
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public void c() {
System.out.println(Thread.currentThread().getName() + ": not synchronized in c()");
/*
* 这里使用this,也可以这样
* Object obj = new Object();
* synchronized (obj)
*/
synchronized (this) {
for(int i = 0; i< 5; i++) {
System.out.println(Thread.currentThread().getName() + ": synchronized in c() for -> " + i);
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public static void doRun() {
Sd01 s = new Sd01();
// 创建一个线程执行a()
new Thread() {
public void run() {
s.a();
}
}.start();
// 创建一个线程执行b()
new Thread() {
public void run() {
s.b();
}
}.start();
// 使用主线程执行c()
s.c();
System.out.println("main thread over");
}
}
/**
* 每个方法使用不同的锁,多个线程调用不同的方法,竞争的是不同的锁,
* 因此调用不同的方法,线程直接不会有锁竞争存在
* @author kevin.chen
*/
class Sd02 {
final byte[] bt = new byte[0]; // 这个比用对象要节约空间,只需执行3行代码完成创建
final Object obj = new Object(); // 需要执行7行代码完成创建
public void a() {
System.out.println(Thread.currentThread().getName() + ": not synchronized in a()");
// 这里使用this对象作为同步锁
synchronized (this) {
for(int i = 0; i< 5; i++) {
System.out.println(Thread.currentThread().getName() + ": synchronized in a() for -> " + i);
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public void b() {
System.out.println(Thread.currentThread().getName() + ": not synchronized in b()");
// 这里使用bt对象作为同步锁
synchronized (bt) {
for(int i = 0; i< 5; i++) {
System.out.println(Thread.currentThread().getName() + ": synchronized in b() for -> " + i);
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public void c() {
System.out.println(Thread.currentThread().getName() + ": not synchronized in c()");
// 这里使用obj对象作为同步锁
synchronized (obj) {
for(int i = 0; i< 5; i++) {
System.out.println(Thread.currentThread().getName() + ": synchronized in c() for -> " + i);
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public static void doRun() {
Sd02 s = new Sd02();
// 创建一个线程执行a()
new Thread() {
public void run() {
s.a();
}
}.start();
// 创建一个线程执行b()
new Thread() {
public void run() {
s.b();
}
}.start();
// 使用主线程执行c()
s.c();
System.out.println("main thread over");
}
}
/**
* 使用Lock来代替synchronized关键字来实现同步操作,
* 所有的线程竞争同一把锁,没有竞争到锁的线程是阻塞的
* @author kevin.chen
*/
class Sd03 {
private Lock lock = new ReentrantLock();
public void a() {
System.out.println(Thread.currentThread().getName() + ": not synchronized in a()");
// 加锁
lock.lock();
try {
for(int i = 0; i< 5; i++) {
System.out.println(Thread.currentThread().getName() + ": synchronized in a() for -> " + i);
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
}
} finally {
// 释放锁
lock.unlock();
}
}
public void b() {
System.out.println(Thread.currentThread().getName() + ": not synchronized in b()");
// 加锁
lock.lock();
try{
for(int i = 0; i< 5; i++) {
System.out.println(Thread.currentThread().getName() + ": synchronized in b() for -> " + i);
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
}
} finally {
// 释放锁
lock.unlock();
}
}
public void c() {
System.out.println(Thread.currentThread().getName() + ": not synchronized in c()");
// 加锁
lock.lock();
try {
for(int i = 0; i< 5; i++) {
System.out.println(Thread.currentThread().getName() + ": synchronized in c() for -> " + i);
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
}
} finally {
// 释放锁
lock.unlock();
}
}
public static void doRun() {
Sd03 s = new Sd03();
// 创建一个线程执行a()
new Thread() {
public void run() {
s.a();
}
}.start();
// 创建一个线程执行b()
new Thread() {
public void run() {
s.b();
}
}.start();
// 使用主线程执行c()
s.c();
System.out.println("main thread over");
}
}
/**
* 使用Lock来代替synchronized关键字来实现同步操作,
* 每个方法使用不同的锁,多个线程调用不同的方法,竞争的是不同的锁,
* 因此调用不同的方法,线程直接不会有锁竞争存在
* @author kevin.chen
*/
class Sd04 {
private Lock lockA = new ReentrantLock();
private Lock lockB = new ReentrantLock();
private Lock lockC = new ReentrantLock();
public void a() {
System.out.println(Thread.currentThread().getName() + ": not synchronized in a()");
// 加锁
lockA.lock();
try {
for(int i = 0; i< 5; i++) {
System.out.println(Thread.currentThread().getName() + ": synchronized in a() for -> " + i);
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
}
} finally {
// 释放锁
lockA.unlock();
}
}
public void b() {
System.out.println(Thread.currentThread().getName() + ": not synchronized in b()");
// 加锁
lockB.lock();
try{
for(int i = 0; i< 5; i++) {
System.out.println(Thread.currentThread().getName() + ": synchronized in b() for -> " + i);
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
}
} finally {
// 释放锁
lockB.unlock();
}
}
public void c() {
System.out.println(Thread.currentThread().getName() + ": not synchronized in c()");
// 加锁
lockC.lock();
try {
for(int i = 0; i< 5; i++) {
System.out.println(Thread.currentThread().getName() + ": synchronized in c() for -> " + i);
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
}
} finally {
// 释放锁
lockC.unlock();
}
}
public static void doRun() {
Sd04 s = new Sd04();
// 创建一个线程执行a()
new Thread() {
public void run() {
s.a();
}
}.start();
// 创建一个线程执行b()
new Thread() {
public void run() {
s.b();
}
}.start();
// 使用主线程执行c()
s.c();
System.out.println("main thread over");
}
}