synchronized 锁住的是对象和类(锁住类和对象有什么区别???),而不是代码。类的每个对象都有一个监视器锁(monitor),当monitor被占用时就会处于锁定状态。
synchronized(锁的对象)可以保证方法或代码块在运行时,同一时刻只有一个线程可以进入到临界区(互斥性),同时它还保证了共享变量的内存可见性。
- 普通同步方法,锁是当前实例对象。 * 静态同步方法,锁是当前类的class对象。 * 同步代码块,锁是括号中的对象。
- 如果Synchronized(类名.class){}.
package com.thread.sync;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author zsw
* @date 2021/1/21 13:41
* @description : synchronized 锁住的是对象和类,而不是代码。类的每个对象都有一个监视器锁(monitor),当monitor被占用时就会处于锁定状态。
*/
@Slf4j
public class SyncCla {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool(); // 创建一个线程池
for (int i = 0; i < 10; i++) {
// 开启10个行程
executorService.submit(new Runnable() {
@Override
public void run() {
testCla testCla = new testCla();
testCla.testSync(); // 结果打印了全部的锁的是SynCla对象 ,再打印结束:{},说明synchronizeds锁的是对象
}
});
}
}
public static class testCla {
// public synchronized void testSync() { //.修饰在方法上,多个线程调用同一个对象的同步方法会阻塞,调用不同对象的同步方法不会阻塞。
public void testSync() {
String obj = new String("zsw");
synchronized (obj) { // 锁的是String对象。
// synchronized (this) { //这个this就是指当前对象(类的实例),多个线程调用同一个对象的同步方法会阻塞,调用不同对象的同步方法不会阻塞。(java对象的内存地址是否相同)
// synchronized (testCla.class) { //锁的对象是testCla.class 类,即testCla类的锁。
log.info("锁的是SynCla对象");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
int i = 0;
i++;
log.info("结束:{}", i);
}
}
}
}
ReentrantLock
package com.thread.sync;
import com.sun.org.apache.xpath.internal.operations.String;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author zsw
* @date 2021/1/21 10:46
* @description :
* java5之后,并发包中新增了Lock接口(以及相关实现类)用来实现锁的功能,它提供了与synchronized关键字类似的同步功能。
* 既然有了synchronized这种内置的锁功能,为何要新增Lock接口?先来想象一个场景:手把手的进行锁获取和释放,先获得锁A,然后再获取锁B,当获取锁B后释放锁A同时获取锁C,当锁C获取后,再释放锁B同时获取锁D,
* 以此类推,这种场景下,synchronized关键字就不那么容易实现了,而使用Lock却显得容易许多。
* 使用方式:
* Lock lock = new ReentrantLock();
* Condition condition = lock.newCondition();
* lock.lock();
* try {
* while(条件判断表达式) {
* condition.wait();
* }
* // 处理逻辑
* } finally {
* lock.unlock();
* }
*需要显示的获取锁,并在finally块中显示的释放锁,目的是保证在获取到锁之后,最终能够被释放。
* -----------------------------------------------------------------
* java中已经有了内置锁:synchronized,synchronized的特点是使用简单,一切交给JVM去处理,不需要显示释放
* 从用法上可以看出,与synchronized相比, ReentrantLock就稍微复杂一点。因为必须在finally中进行解锁操作,如果不在 finally解锁,有可能代码出现异常锁没被释放,
*ReentrantLock的性能是明显优于synchronized的,ReentrantLock在功能上更加丰富,它具有可重入、可中断、可限时、公平锁等特点。
*/
public class ReentrantLockTest extends Thread {
public static ReentrantLock lock = new ReentrantLock();
public static int i=0;
public ReentrantLockTest(java.lang.String thread1) {
super.setName(thread1);
}
@Override
public void run() {
for (int j = 0; j < 1000; j++) {
lock.lock();
try {
System.out.println(this.getName() + " " + i);
i++;
} finally {
lock.unlock();
}
}
}
public static void main(String[] args) {
ReentrantLockTest thread1 = new ReentrantLockTest("thread1");
ReentrantLockTest thread2 = new ReentrantLockTest("thread2");
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
}
}