***模式之 Balking **
定义
Balking (犹豫)模式用在一个线程发现另一个线程或本线程已经做了某一件相同的事,那么本线程就无需再做了,直接结束返回
实现
让monitor线程只创建并执行一遍
实现1:
public class TestInterrupt3 {
public static void main(String[] args) throws InterruptedException {
TwoPhaseTermination tpt = new TwoPhaseTermination();
tpt.start();
for (int i = 0; i < 10; i++) {
new Thread(() -> {
tpt.start();
}).start();
}
}
}
@Slf4j
class TwoPhaseTermination {
private Thread monitor;
private volatile boolean isStop; // 是否停止
// 用来表示是否已经有线程已经在执行启动了
private volatile boolean starting = false; // start方法是否已调用过?目的是让监控线程只创建一次;false为没启动过
public void start() {
// 这里对当前对象的starting这个共享成员变量既有读操作,又有写操作,
// 所以当发生线程上下文切换的时候,有可能发生线程安全问题
if (!starting) { // 第一重判断,如果启动过,那么直接就不会走if里面,省去了检查锁的步骤。
// 当只要第一次出现线程安全问题时,去加锁即可,后面就不用再去加锁了
synchronized (this) { // 如果过了第一重判断,那么接下来,就有可能出现线程安全问题,此时才去加锁
if (!starting) { // 第二重判断,目的是防止多线程并发访问
monitor = new Thread() {
@Override
public void run() {
while (true) {
if (isStop) {
log.debug("监控线程被打断,料理后事");
break;
}
// 每隔1秒执行一次监控
try {
Thread.sleep(1000);
log.debug("....执行监控....");
} catch (InterruptedException e) {
isStop = true;
}
}
}
};
monitor.start();
starting = true;
}
}
}
}
public void stop() {
if (monitor != null) {
isStop = true;
monitor.interrupt(); // 打断monitor,即便monitor线程在sleep状态中,让monitor抛出异常
}
}
}
实现2:
public class TestInterrupt3 {
public static void main(String[] args) throws InterruptedException {
TwoPhaseTermination tpt = new TwoPhaseTermination();
tpt.start();
for (int i = 0; i < 10; i++) {
new Thread(() -> {
tpt.start();
}).start();
}
}
}
@Slf4j
class TwoPhaseTermination {
private Thread monitor;
private volatile boolean isStop; // 是否停止
private volatile boolean starting = false; // start方法是否已调用过?目的是让监控线程只创建一次;false为没启动过
public void start() {
// 相对于上面这种来说,这里存在一个不足,就是: 这里每次都要检查这把锁,而上面的写法当且仅当第一次如果发生线程安全
// 问题时,才会去加锁。
synchronized (this) { // 这里把对共享变量的读写操作使用synchronized保护起来,把对monitor的线程放到外面
if (starting) { // 体现了我们在使用锁的时候,只保护应该去保护的代码,而不要把其它不怎么相关的代码放到
return; // 保护区里面
}
starting = true;
}
monitor = new Thread() {
@Override
public void run() {
while (true) {
if (isStop) {
log.debug("监控线程被打断,料理后事");
break;
}
// 每隔1秒执行一次监控
try {
Thread.sleep(1000);
log.debug("....执行监控....");
} catch (InterruptedException e) {
isStop = true;
}
}
}
};
monitor.start();
starting = true;
}
public void stop() {
if (monitor != null) {
isStop = true;
monitor.interrupt(); // 打断monitor,即便monitor线程在sleep状态中,让monitor抛出异常
}
}
}