synchronized
- 对象锁
- 锁this对象:synchronized(this) { }
- 锁非静态变量:synchronized(object) { }
- 锁非静态方法:private synchronized void syncMethod( ){ }
- 类锁
- 锁类的class:synchronized(类.class) { }
- 锁静态变量:static Object object;synchronized(object) { }
- 锁静态方法:private synchronized static void syncMethod( ){ }
一个类只有一个类锁。一个类可以创建很多对象,每个对象都有各自的对象锁,对象锁间互不影响。
对象锁和类锁也互不影响。
对象锁
@Slf4j
public class SyncThread implements Runnable {
private final Object obj = new Object(); //非静态变量
@Override
public void run() {
syncMethod();
}
private void syncMethod() {
log.info("thread in");
synchronized (obj) { //获取非静态变量的锁
try {
log.info("thread start");
TimeUnit.SECONDS.sleep(2);
log.info("thread end");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Main {
public static void main(String[] args) {
SyncThread syncThread = new SyncThread();
new Thread(new SyncThread(), "thread-1").start();
new Thread(new SyncThread(), "thread-2").start();
new Thread(syncThread, "thread-3").start();
new Thread(syncThread, "thread-4").start();
}
}
thread-1和thread-2是生成了两个SyncThread对象,这两个SyncThread对象又有各自的Object对象,所以thread-1和thread-2可以获取各自的对象锁,互不影响。
thread-3和thread-4公用一个SyncThread对象,共同竞争一个SyncThread对象的Object对象的锁,存在互斥。
thread-1,thread-2,thread-3或thread-1,thread-2,thread-4间是不同的对象锁,互不影响。
@Slf4j
public class SyncThread implements Runnable {
@Override
public void run() {
syncMethod();
}
private void syncMethod() {
log.info("thread in");
synchronized (this) { // 获取this对象的锁
try {
log.info("thread start");
TimeUnit.SECONDS.sleep(2);
log.info("thread end");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
thread-1和thread-2获取各自匿名对象SyncThread对象的锁,是当前线程类的对象的锁,而在上面的非静态变量对象锁,是当前线程类的对象的非静态实例变量的对象锁,多了一层,效果一样。
@Slf4j
public class SyncThread implements Runnable {
@Override
public void run() {
syncMethod();
}
private synchronized void syncMethod() { // 非静态方法的对象锁
log.info("thread in");
try {
log.info("thread start");
TimeUnit.SECONDS.sleep(2);
log.info("thread end");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
这种对象锁应该和this锁一样,都是当前线程类的对象的锁。
类锁
@Slf4j
public class SyncThread implements Runnable {
@Override
public void run() {
syncMethod();
}
private void syncMethod() {
log.info("thread in");
synchronized (SyncThread.class) {
try {
log.info("thread start");
TimeUnit.SECONDS.sleep(2);
log.info("thread end");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
thread-1,thread-2,thread-3,thread-4的线程对象都是同一个类创建的,他们竞争同一个类锁,所以这4个线程都存在互斥关系。
@Slf4j
public class SyncThread implements Runnable {
private static final Object lock = new Object(); //静态变量
@Override
public void run() {
syncMethod();
}
private void syncMethod() {
log.info("thread in");
synchronized (lock) { //获取静态变量的锁
try {
log.info("thread start");
TimeUnit.SECONDS.sleep(2);
log.info("thread end");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
因为静态变量是类变量,各个对象共有,所以静态变量的锁也是类锁,效果和上面一样。
@Slf4j
public class SyncThread implements Runnable {
@Override
public void run() {
syncMethod();
}
private synchronized static void syncMethod() { //获取静态方法的锁
log.info("thread in");
try {
log.info("thread start");
TimeUnit.SECONDS.sleep(2);
log.info("thread end");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
静态方法和静态变量一样,都是类的,不是某个对象的,所以是类锁,同样效果和上面一样。
线程通信
class Main {
public static void main(String[] args) throws InterruptedException{
Object obj = new Object();
for (int i = 0; i < 5; i++) {
new Thread(()->{
synchronized (obj){
System.out.println("thread start");
try {
obj.wait(); //放弃锁,自我阻塞
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("thread end");
}
}).start();
}
System.out.println("main start");
Thread.sleep(2000);
synchronized (obj){ //申请锁资源
obj.notifyAll(); //唤醒其他所有线程,这些线程再竞争锁资源
, }
System.out.println("main end");
}
}
ReentrantLock
ReentrantLock lock = new ReentrantLock();
for (int i = 0; i < 5; i++) {
new Thread(()->{
try {
lock.lock();
System.out.println("hello");
Thread.sleep(2000);
lock.unlock();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}).start();
}
ReentrantLock lock = new ReentrantLock();
for (int i = 0; i < 5; i++) {
new Thread(()->{
boolean b=false;
try {
b=lock.tryLock();
if (b){
System.out.println("hello");
Thread.sleep(2000);
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}finally {
if (b){
lock.unlock();
}
}
}).start();
}
tryLock()会试图去获取锁,如果获取成功返回true,如果获取失败,则放弃并返回false,并且不会阻塞。
还可以传入时间,表示最多等待的时间。
线程通信
ReentrantLock lock = new ReentrantLock();
Condition c1 = lock.newCondition();
for (int i = 0; i < 5; i++) {
new Thread(()->{
try {
lock.lock();
c1.await(); //放弃锁,自我阻塞
System.out.println("hello");
Thread.sleep(1000);
lock.unlock();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}).start();
}
Thread.sleep(2000);
lock.lock(); //先拥有锁资源
c1.signalAll(); //唤醒其他所有线程
lock.unlock();
可以创建多个Condition完成较复杂的通信