package com.my.sync;
public class Phone {
public synchronized void sendMes() {
System.out.println("method 1:sendMes");
}
public synchronized void sendEmail() {
System.out.println("method 2:sendEmail");
}
}
Phone phone = new Phone();
new Thread(() -> {
phone.sendMes();
}, "AA").start();
new Thread(() -> {
phone.sendEmail();
}, "BB").start();
method 1:sendMes
method 2:sendEmail
package com.my.sync;
import java.util.concurrent.TimeUnit;
public class Phone {
public synchronized void sendMes() {
try {
TimeUnit.SECONDS.sleep(4);
System.out.println("method 1:sendMes");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void sendEmail() {
System.out.println("method 2:sendEmail");
}
}
Phone phone = new Phone();
new Thread(() -> {
phone.sendMes();
}, "AA").start();
new Thread(() -> {
phone.sendEmail();
}, "BB").start();
method 1:sendMes
method 2:sendEmail
package com.my.sync;
import java.util.concurrent.TimeUnit;
public class Phone {
public synchronized void sendMes() {
try {
TimeUnit.SECONDS.sleep(4);
System.out.println("method 1:sendMes");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void sendHello() {
System.out.println("method 3:sendHello");
}
}
Phone phone = new Phone();
new Thread(() -> {
phone.sendMes();
}, "AA").start();
new Thread(() -> {
phone.sendHello();
}, "BB").start();
method 3:sendHello
method 1:sendMes
package com.my.sync;
import java.util.concurrent.TimeUnit;
public class Phone {
public synchronized void sendMes() {
try {
TimeUnit.SECONDS.sleep(4);
System.out.println("method 1:sendMes");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void sendEmail() {
System.out.println("method 2:sendEmail");
}
}
Phone p1 = new Phone();
Phone p2 = new Phone();
new Thread(() -> {
p1.sendMes();
}, "AA").start();
new Thread(() -> {
p2.sendEmail();
}, "BB").start();
method 2:sendEmail
method 1:sendMes
package com.my.sync;
import java.util.concurrent.TimeUnit;
public class Phone {
public static synchronized void sendMes() {
try {
TimeUnit.SECONDS.sleep(4);
System.out.println("method 1:sendMes");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static synchronized void sendEmail() {
System.out.println("method 2:sendEmail");
}
}
Phone phone = new Phone();
new Thread(() -> {
phone.sendMes();
}, "AA").start();
new Thread(() -> {
phone.sendEmail();
}, "BB").start();
method 1:sendMes
method 2:sendEmail
package com.my.sync;
import java.util.concurrent.TimeUnit;
public class Phone {
public static synchronized void sendMes() {
try {
TimeUnit.SECONDS.sleep(4);
System.out.println("method 1:sendMes");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static synchronized void sendEmail() {
System.out.println("method 2:sendEmail");
}
}
Phone p1 = new Phone();
Phone p2 = new Phone();
new Thread(() -> {
p1.sendMes();
}, "AA").start();
new Thread(() -> {
p2.sendEmail();
}, "BB").start();
method 1:sendMes
method 2:sendEmail
package com.my.sync;
import java.util.concurrent.TimeUnit;
public class Phone {
public synchronized void sendMes() {
try {
TimeUnit.SECONDS.sleep(4);
System.out.println("method 1:sendMes");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void sendEmail() {
System.out.println("method 2:sendEmail");
}
}
Phone phone = new Phone();
new Thread(() -> {
phone.sendMes();
}, "AA").start();
new Thread(() -> {
phone.sendEmail();
}, "BB").start();
method 2:sendEmail
method 1:sendMes
package com.my.sync;
import java.util.concurrent.TimeUnit;
public class Phone {
public static synchronized void sendMes() {
try {
TimeUnit.SECONDS.sleep(4);
System.out.println("method 1:sendMes");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void sendEmail() {
System.out.println("method 2:sendEmail");
}
}
Phone p1 = new Phone();
Phone p2 = new Phone();
new Thread(() -> {
p1.sendMes();
}, "AA").start();
new Thread(() -> {
p2.sendEmail();
}, "BB").start();
method 2:sendEmail
method 1:sendMes
情况 1 - 情况 2:同一对象访问不同同步锁
情况 3:同一对象访问同步锁与不同步锁
情况 4:不同对象访问不同同步锁
情况 5:同一对象访问不同静态同步锁
情况 6:不同对象访问不同静态同步锁
情况 7:同一对象访问静态同步锁和同步锁
情况 8:不同对象访问静态同步锁与同步锁
synchronized 实现同步的基础是 Java 中的每一个对象都可以作为锁,具体表现为以下 3 种形式
对于普通同步方法,synchronized 锁的是当前实例对象
对于静态同步方法,synchronized 锁的是当前类的 Class 对象
对于同步方法块,synchronized 锁的是 Synchonized 括号里配置的对象
一个对象里面如果有多个非静态同步方法,某一个时刻,只要有一个线程去调用了其中的一个非静态同步方法,其它的线程都只能等待,即某一个时刻内,只能有一个线程去访问这些非静态同步方法
非静态同步方法锁的是当前对象(this),被锁后,其它线程都不能进入到当前对象的其它的非静态同步方法
当一个线程试图访问同步代码块时,首先必须得到锁,退出或抛出异常时必须释放锁,也就是说如果一个实例对象的非静态同步方法获取锁后,该实例对象的其他非静态同步方法必须等待获取锁的方法释放锁后才能获取锁
不同实例对象的非静态同步方法使用不同的锁,但是所有的静态同步方法使用同一把锁,即类对象本身,这两把锁锁的是两个不同的对象,所以静态同步方法与非静态同步方法之间不会有竞争
一旦一个静态同步方法获取锁后,其他的静态同步方法都必须等待该方法释放锁后才能获取锁,不管是同一个实例对象的静态同步方法之间,还是不同的实例对象的静态同步方法之间都是如此,因为它们是同一个类的实例对象
公平锁效率相对低
非公平锁效率高,但是线程容易饿死
ReentrantLock lock = new ReentrantLock(false);
ReentrantLock lock = new ReentrantLock(false);
// 或
ReentrantLock lock = new ReentrantLock();
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
} else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
synchronized 和 Lock 都是可重入锁
sychronized 是隐式锁,不用手工上锁与解锁,而 Lock 为显示锁,需要手工上锁与解锁
可重入锁也叫递归锁,有了可重入锁之后,破解第一把之后就可以一直进入到内层结构
package com.my.reentrylock;
public class SynchronizedRLockTest {
public static void main(String[] args) {
Object obj = new Object();
new Thread(() -> {
synchronized (obj) {
System.out.println(Thread.currentThread().getName() + " 外层");
synchronized (obj) {
System.out.println(Thread.currentThread().getName() + " 中层");
synchronized (obj) {
System.out.println(Thread.currentThread().getName() + " 内层");
}
}
}
}, "AA").start();
}
}
public synchronized void add() {
add();
}
package com.my.reentrylock;
import java.util.concurrent.locks.ReentrantLock;
public class LockRLockTest {
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
new Thread(() -> {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + " 外层");
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + " 内层");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}, "BB").start();
}
}
ReentrantLock lock = new ReentrantLock();
new Thread(() -> {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + " 外层");
lock.lock();
System.out.println(Thread.currentThread().getName() + " 内层");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}, "BB").start();
new Thread(() -> {
lock.unlock();
System.out.println(Thread.currentThread().getName());
lock.unlock();
}, "BB").start();
private ReentrantLock lock = new ReentrantLock();
public void add() {
lock.lock();
add();
lock.unlock();
}
系统资源不足
系统资源分配不当
进程运行顺序不当
package com.my.deadlock;
import java.util.concurrent.TimeUnit;
public class DeadlockTest {
public static void main(String[] args) {
Object a = new Object();
Object b = new Object();
new Thread(() -> {
synchronized (a) {
System.out.println(Thread.currentThread().getName() + " 持有锁 a,试图获取锁 b");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (b) {
System.out.println(Thread.currentThread().getName() + " 获取锁 b");
}
}
}, "AA").start();
new Thread(() -> {
synchronized (b) {
System.out.println(Thread.currentThread().getName() + " 持有锁 b,试图获取锁 a");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (a) {
System.out.println(Thread.currentThread().getName() + " 获取锁 a");
}
}
}, "BB").start();
}
}
jps:类似于 Linux 中的 ps -ef 命令
jstack:JVM 自带的堆栈跟踪工具
jps -l
jstack 【进程号】