1.单项阻塞
block方法直接阻塞当前代码,等待其他线程执行release方法后,阻塞代码直接释放
测试代码:
/**
* 阻塞释放与锁对象
*/
public class BlockLock {
public BlockLock() {
}
public void block() {
synchronized (this) {//阻塞代码
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 释放锁
*
* @return 是否成功释放
*/
public void release() {
synchronized (this) {//释放代码,释放阻塞
this.notify();
}
}
public static void main(String[] args) throws InterruptedException {
BlockLock blockLock = new BlockLock();
BlockLock blockLock1 = new BlockLock();
new Thread(() -> {
try {
Thread.sleep(2000);//释放需要在阻塞完成之后执行,所以此处加入休眠时间保证blockLock.block()已经执行
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("释放");
blockLock.release();//释放阻塞,释放需要在阻塞完成之后执行
System.out.println("释放完成");
}).start();
System.out.println("阻塞");
blockLock.block();//阻塞后续代码执行
System.out.println("释放完成后续逻辑");
}
}
注意,释放代码必须在阻塞block() 完成之后再执行释放release(), 否则释放release() 不生效
运行结果
2.双向阻塞
双向阻塞,如果没有执行阻塞block() 而直接执行release(), release()相当于阻塞,必须等待block()之后,release()才会执行,并将block() 释放 .....
效果为两个方法相互阻塞释放: a方法执行后阻塞 执行b方法后 a方法才能释放阻塞,同时b方法进入阻塞 a方法与b方法都能控制对方释放阻塞同时自身进入阻塞
/**
* 阻塞释放与锁对象
*/
public class BlockLock {
private boolean status;//是否已经阻塞
private boolean sleepStatus;//是否使用休眠
private long millis;//等待锁的休眠时间
/**
* 阻塞构建
*/
public BlockLock() {
this.status = false;
this.sleepStatus = false;
}
/**
* 阻塞休眠构建
* 对资源性能有限,可以使用此种方式
*
* @param millis
*/
public BlockLock(long millis) {
this.status = false;
this.sleepStatus = true;
this.millis = millis;
}
/**
* 阻塞锁
*/
public void block() throws InterruptedException {
synchronized (this) {//阻塞代码
status = true;
this.wait();
}
}
/**
* 阻塞释放锁,如果没有阻塞,当前方法会阻塞,直到需要释放的阻塞出现
*/
public void blockRelease() throws InterruptedException {
while (true) {
synchronized (this) {//释放代码,释放阻塞
if (status) {
status = false;//切换状态
this.notify();
return;
}
}
if (this.sleepStatus) {
Thread.sleep(millis);//等待阻塞,释放cpu,使用休眠,节省cpu消耗,目前没有找到更好的实现方式
} else {
Thread.yield();//切换cpu时间片,低延迟,高性能,比while死循环自动切换cpu性能要好
}
}
}
/**
* 释放锁,如果没有阻塞,当前方法忽略
*/
public void release() throws InterruptedException {
synchronized (this) {//释放代码,释放阻塞
if (!status) return;//不存在需要释放的锁
status = false;//切换状态
this.notify();
}
}
public static void main(String[] args) {
BlockLock blockLock = new BlockLock();
final int max = 100000;
new Thread(() -> {//释放阻塞,释放阻塞与阻塞数需要保持一致
long startTime = System.currentTimeMillis();
for (int i = 0; i < max; i++) {
try {
blockLock.blockRelease();//释放阻塞,释放需要在阻塞完成之后执行,否则会阻塞
System.out.println("解锁" + i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
long endTime = System.currentTimeMillis();
long time = endTime - startTime;
System.out.println("消耗时间[" + time + "] ms");
}).start();
new Thread(() -> {
for (int i = 0; i < max; i++) {
try {
blockLock.block();//阻塞后续代码执行
System.out.println("上锁" + i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
运行结果
3.双向阻塞优化
/**
* 阻塞释放与锁对象
*/
public class BlockLock {
private Object lock;//临时阻塞对象
private boolean status;//是否已经阻塞
private boolean sleepStatus;//是否使用休眠
private long millis;//等待锁的休眠时间
/**
* 阻塞构建
*/
public BlockLock() {
this.status = false;
this.sleepStatus = false;
this.lock = new String();
}
/**
* 阻塞休眠构建
* 对资源性能有限,可以使用此种方式
*
* @param millis
*/
public BlockLock(long millis) {
this.status = false;
this.sleepStatus = true;
this.millis = millis;
this.lock = new String();
}
/**
* 阻塞锁
*/
public void block() throws InterruptedException {
synchronized (this) {//阻塞代码
if (!status && !sleepStatus) {//减少锁次数与双向阻塞
synchronized (lock) {
status = true;
lock.notify();
}
} else {
status = true;
}
this.wait();
}
}
public long count = 0;
/**
* 阻塞释放锁,如果没有阻塞,当前方法会阻塞,直到需要释放的阻塞出现
*/
public void blockRelease() throws InterruptedException {
while (true) {
count++;
synchronized (this) {//释放代码,释放阻塞
if (status) {
status = false;//切换状态
this.notify();
return;
}
}
if (sleepStatus) {
Thread.sleep(millis);//休眠
continue;
}
synchronized (lock) {//双向阻塞,性能优于 释放cpu时间片
if (!status) lock.wait();
}
}
}
/**
* 释放锁,如果没有阻塞,当前方法忽略
*/
public void release() throws InterruptedException {
synchronized (this) {//释放代码,释放阻塞
if (!status) return;//不存在需要释放的锁
status = false;//切换状态
this.notify();
}
}
public static void main(String[] args) {
BlockLock blockLockOne = new BlockLock();
final int max = 1000000;
new Thread(() -> {
long startTime = System.currentTimeMillis();
for (int i = 0; i < max; i++) {
try {
if(i%100000==0) {
System.out.println("解锁: " + i);
}
blockLockOne.blockRelease();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("计算总次数:" + blockLockOne.count);
System.out.println("累计时间: " + (System.currentTimeMillis() - startTime)+"ms");
}).start();
new Thread(() -> {
for (int i = 0; i < max; i++) {
try {
blockLockOne.block();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
运行结果:
4.阻塞控制
public abstract class MyThread extends Thread {
private boolean suspend = false;
private int time;
private String control = ""; // 只是需要一个对象而已,这个对象没有实际意义
public BonreeThread(int time) {
this.time = time;
}
public void setSuspend(boolean suspend) {
if (!suspend) {
synchronized (control) {
control.notifyAll();
}
}
this.suspend = suspend;
}
public void run() {
while (true) {
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (control) {
if (suspend) {
try {
control.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
this.runPersonelLogic();
}
}
protected abstract void runPersonelLogic();
//测试主方法
public static void main(String[] args) throws InterruptedException {
MyThread myThread = new MyThread(1000) {
@Override
protected void runPersonelLogic() {//这个方法会重复执行
System.out.println("执行");
}
};
myThread .start();
myThread .setSuspend(true);//阻塞bonreeThread内的runPersonelLogic()方法
myThread .setSuspend(false);//取消阻塞bonreeThread内的runPersonelLogic()方法
}
}