中断异常测试

x33g5p2x  于2021-12-18 转载在 其他  
字(4.2k)|赞(0)|评价(0)|浏览(289)

在测试中断异常前我们先了解一下 sleep 和 wait 的本质区别:sleep 不会释放同步锁,wait 会释放同步锁

抛出中断异常后会释放同步锁

1. sleep

1.1 synchronized

测试代码如下:

public class Sleep {
    public static void main(String[] args) {
        Object o = new Object();
        Thread t = new Thread(() -> {
            synchronized (o) {
                try {
                    System.out.println("t start");
                    TimeUnit.SECONDS.sleep(Long.MAX_VALUE);
                    System.out.println("t end");
                } catch (InterruptedException e) {
                    System.out.println("t interrupted......");
                }
            }
        });
        t.start();
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t.interrupt();
    }
}

控制台输出如下:

t1 start
t1 interrupted......

1.2 lock

测试代码如下:

public class Sleep {
    public static void main(String[] args) {
        Lock lock = new ReentrantLock();
        Thread t = new Thread(() -> {
                try {
                    lock.lock();
                    System.out.println("t start");
                    TimeUnit.SECONDS.sleep(Long.MAX_VALUE);
                    System.out.println("t end");
                } catch (InterruptedException e) {
                    System.out.println("t interrupted......");
                } finally {
                    lock.unlock();
                }
        });
        t.start();
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t.interrupt();
    }
}

控制台输出如下:

t start
t interrupted......

由以上两个测试我们可以得知:线程在通过 sleep 方法进入超时等待状态时是可以响应中断的。

2. wait

使用 wait 方法同样可以响应中断。

3. join

使用 join 方法后同样可以响应中断。

当前线程调用 join 方法也可以阻塞当前线程本身,测试代码如下:

public class Join {
    public static void main(String[] args) {
        System.out.println(System.currentTimeMillis());
        System.out.println("1");
        System.out.println("1");
        try {
            Thread.currentThread().join(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("1");
        System.out.println("1");
        System.out.println(System.currentTimeMillis());
    }
}

控制台输出如下:

1608960108281
1
1
1
1
1608960113282

4. 阻塞状态下可以响应中断吗

对于 synchronized 来说,阻塞状态下是无法响应中断的,对于 lock 来说,调用 lock() 方法进入阻塞状态后同样无法响应中断,但 lock 提供了另一个方法可以用来响应中断:lockInterruptibly()

synchronized 测试代码如下:

public class Test {
    public static void main(String[] args) {
        Object o = new Object();
        Thread t1 = new Thread(() -> {
            synchronized (o) {
                try {
                    System.out.println("t1 start");
                    TimeUnit.SECONDS.sleep(Long.MAX_VALUE);
                    System.out.println("t1 end");
                } catch (InterruptedException e) {
                    System.out.println("t1 interrupted");
                }
            }
        });
        t1.start();
        Thread t2 = new Thread(() -> {
            synchronized (o) {
                try {
                    System.out.println("t1 start");
                    TimeUnit.SECONDS.sleep(5);
                    System.out.println("t1 end");
                } catch (InterruptedException e) {
                    System.out.println("t1 interrupted");
                }
            }
        });
        t2.start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t2.interrupt();
    }
}

控制台输出如下:

t1 start

lock() 测试代码如下:

public class T04_ReentrantLock4 {
    public static void main(String[] args) {
        ReentrantLock lock = new ReentrantLock();
        Thread t1 = new Thread(() -> {
            try {
                lock.lock();
                System.out.println("t1 start");
                TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
                System.out.println("t1 end");
            } catch (InterruptedException e) {
                System.out.println("t1 Interrupted......");
            } finally {
                lock.unlock();
            }
        });
        t1.start();

        Thread t2 = new Thread(() -> {
            try {
                lock.lock();
// lock.lockInterruptibly();
                System.out.println("t2 start");
                TimeUnit.SECONDS.sleep(5);
                System.out.println("t2 end");
            } catch (InterruptedException e) {
                System.out.println("t2 Interrupted......");
            } finally {
                // 这里不加 lock.unlock(); 是因为当前线程根本没有获取锁,中断异常被 catch 捕获前肯定要先执行 finally 里的代码,但没有获取锁就释放锁是会抛异常的,不信你可以试试
            }
        });
        t2.start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t2.interrupt();
    }
}

控制台输出如下:

t1 start

线程 t2 由于没有获取对象锁,所以进入阻塞状态,无法响应中断。

我们再来看看另一种测试方法,lockInterruptibly() 代码如下:

public class T04_ReentrantLock4 {
    public static void main(String[] args) {
        ReentrantLock lock = new ReentrantLock();
        Thread t1 = new Thread(() -> {
            try {
                lock.lock();
                System.out.println("t1 start");
                TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
                System.out.println("t1 end");
            } catch (InterruptedException e) {
                System.out.println("t1 Interrupted......");
            } finally {
                lock.unlock();
            }
        });
        t1.start();

        Thread t2 = new Thread(() -> {
            try {
// lock.lock();
                lock.lockInterruptibly();
                System.out.println("t2 start");
                TimeUnit.SECONDS.sleep(5);
                System.out.println("t2 end");
            } catch (InterruptedException e) {
                System.out.println("t2 Interrupted......");
            } finally {
		        // 这里不加 lock.unlock(); 是因为当前线程根本没有获取锁,中断异常被 catch 捕获前肯定要先执行 finally 里的代码,但没有获取锁就释放锁是会抛异常的,不信你可以试试
            }
        });
        t2.start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t2.interrupt();
    }
}

控制台输出如下:

t1 start
t2 Interrupted......

相关文章