目录
Synchronized关键字的用法:
1,修饰实例方法: synchronized 修饰实例方法, 则用到的锁,默认为 this 当前方法调用对象;
2,修饰静态方法: synchronized 修饰静态方法, 则其所用的锁,默认为 Class 对象;
3 ,修饰代码块: synchronized 修饰代码块, 则其所用的锁,是某个指定 Java 对象,例如Object obj;
修饰实例方法:
// 计数器类
public class Counter1 {
// 用于计数的公共变量
public static int count = 0;
// 递增
public void add() {
for (int i = 0; i < 10000; i++) {
synchronized (this) {
Counter1.count += 1;
}
}
}
// 递减
public void dec() {
for (int i = 0; i < 10000; i++) {
synchronized (this) {
Counter1.count -= 1;
}
}
}
}
public class Test1 {
public static void main(String[] args) throws InterruptedException {
Counter1 count1 = new Counter1();
Thread add = new Thread() {
@Override
public void run() {
count1.add();
}
};
Thread dec = new Thread(){
@Override
public void run() {
count1.dec();
}
};
add.start();
dec.start();
add.join();
dec.join();
System.out.println(Counter1.count);
}
}
运行结果:
修饰静态方法:
public class Counter2 {
// 用于计数的公共变量
public static int count = 0;
// 递增
public void add() {
for (int i = 0; i < 10000; i++) {
synchronized (this.getClass()) {
Counter1.count += 1;
}
}
}
// 递减
public void dec() {
for (int i = 0; i < 10000; i++) {
synchronized (this.getClass()) {
Counter1.count -= 1;
}
}
}
}
public class Test2 {
public static void main(String[] args) throws InterruptedException {
Counter2 count2 = new Counter2();
Thread add = new Thread() {
@Override
public void run() {
count2.add();
}
};
Thread dec = new Thread(){
@Override
public void run() {
count2.dec();
}
};
add.start();
dec.start();
add.join();
dec.join();
System.out.println(Counter2.count);
}
}
运行结果:
修饰代码块:
public class Counter4 {
// 用于计数的公共变量
public static int count = 0;
public static final Object obj = new Object();
// 递增
public void add() {
for (int i = 0; i < 10000; i++) {
synchronized (obj) {
Counter4.count += 1;
}
}
}
// 递减
public void dec() {
for (int i = 0; i < 10000; i++) {
synchronized (obj) {
Counter4.count -= 1;
}
}
}
}
public class Test4 {
public static void main(String[] args) throws InterruptedException {
Counter4 count4 = new Counter4();
Thread add = new Thread() {
@Override
public void run() {
count4.add();
}
};
Thread dec = new Thread() {
@Override
public void run() {
count4.dec();
}
};
add.start();
dec.start();
add.join();
dec.join();
System.out.println(Counter4.count);
}
}
运行结果:
当一个线程访问对象的一个 synchronized(this) 同步代码块时,另一个线程仍然可 以访问该对象中的非 synchronized(this) 同步代码块。
父类中 synchronized 修饰的方法,如果子类没有重写,则该方法仍然是线程安全性;如果子类重写,并且没有使用 synchronized 修饰,则该方法不是线程安全的;
在定义接口方法时,不能使用 synchronized 关键字;
构造方法不能使用 synchronized 关键字,但可以使用 synchronized 代码块来进 行同步; 离开 synchronized 代码块后,该线程所持有的锁,会自动释放;
ReentrantLock
synchronized 关键字虽然已经实现可重入锁,但由于获取时必须一直等待,没有额外的 尝试机制。所以,在 java.util.concurrent.locks 包提供的 ReentrantLock 用于替代 sy nchronized 。顾名思义, ReentrantLock 也是可重入锁,它和 synchronized 一样,一个线程可以多次获取同一个锁。
public class Reentrant {
public static void main(String[] args) throws InterruptedException {
Counter count = new Counter();
Thread add = new Thread() {
@Override
public void run() {
count.add();
}
};
Thread dec = new Thread() {
@Override
public void run() {
count.dec();
}
};
add.start();
dec.start();
add.join();
dec.join();
System.out.println(Counter1.count);
}
}
class Counter {
private static int count = 0;
private final ReentrantLock lock = new ReentrantLock();
public void add() {
for (int i = 0; i < 50; i++) {
lock.lock();
try {
count += 1;
} finally {
lock.unlock();
}
}
}
public void dec() {
for (int i = 0; i < 50; i++) {
lock.lock();
try {
count -= 1;
} finally {
lock.unlock();
}
}
}
}
运行结果:
ReentrantLock 总共有三个内部类: Sync 、 NonfairSync 、 FairSync 。
NonfairSync 类继承了 Sync 类,表示采用非公平策略获取锁:每一次都尝试获取锁,不会按照公平等待的原则进行等待,不会让等待时间最久的线程获得锁。
FairSync 类也继承了 Sync 类,表示采用公平策略获取锁:当资源空闲时,它总是会先判断 sync 队列是否有等待时间更长的线程,如果存在,则将当前线程加入到等待队列的尾部,实现了公平获 取原则。
ReentrantLock 构造函数:默认是采用的非公平策略获取锁。
ReentrantLock与Synchronized的区别
ReentrantLock | Synchronized | |
锁实现机制 | AQS | 监视器Monitor |
获取锁 | 可以通过tryLock()尝试获取锁,更灵活 | 线程抢占模型 |
释放锁 | 必须显示通过unlock()释放锁 | 自动释放 |
锁类型 | 支持公平锁和非公平锁 | 非公平锁 |
可重入性 | 可重入 | 可重入 |