3.线程一共有哪些状态呢(二)?

在上一章中介绍了使线程进入timed_waiting状态的3种方法

1. Thread.sleep(long)
2. Object.wait(long)
3. Thread.join(long)

接下来继续实战使线程进入BLOCKED状态的方法

synchronized会使线程进入BLOCKED状态


/**
 * synchronized线程处于timed_waiting状态
 *
 * @author jinglei
 * @date 2020/8/21 13:09
 */
public class TimedWaitingBySync {

    private static Object lock = new Object();

    public static void main(String[] args) {

        Thread syncLongThread = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock){
                    System.out.println("子线程无法进入同步代码块");
                }

            }
        });
        syncLongThread.setName("mythread-sync");

        //启动线程
        syncLongThread.start();
        //注意,这个地方并不一定会保证主线程优先于子线程执行,具体哪个线程先执行是由CPU根据当时的系统资源调度的,
        // 尽管大部分情况可能看到是主线程优先执行
        synchronized (lock){
            while(true){
            }
        }
    }

}

按照如下步骤查看线程堆栈
3.线程一共有哪些状态呢(二)?_第1张图片

堆栈内容如下
3.线程一共有哪些状态呢(二)?_第2张图片
可以看出线程进入了BLOCKED状态,并且是在一个对象锁或者是对象监视器上阻塞,以后看到这种日志就是说明此线程需要获取一个对象锁,但是这个锁已经被其他线程占有了,该线程只能进入阻塞队列等待其他线程释放锁。

谈到synchronized就不得不说下经典的死锁问题,死锁指的是两个及其以上线程在分别持有了相应的锁的同时,还需要对方已经持有的锁,并且自身已经持有的锁不会主动去释放,此时就形成了一个死循环,也就是死锁。

现实生活中的例子,比如有一双筷子,李梅和韩雷雷分别拥有了一根筷子,他们都不会把自己的筷子给别人还想要对方的筷子,这就构成了死锁。

废话不继续了,上代码


/**
 * sync导致的死锁
 *
 * @author jinglei
 * @date 2020/8/24 16:22
 */
public class SyncDeadLock {

    private static Object tLock = new Object();
    private static Object sLock = new Object();

    static class Teacher implements Runnable{

        @Override
        public void run() {
            synchronized (tLock){
                System.out.println("老师持有了tLock锁,还需要获取sLock锁");
                try {
                    //休眠1秒为了让Student有时间去获取sLock锁
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (sLock){
                    System.out.println("老师更新成绩");
                }
            }
        }
    }

    static class Student implements Runnable {
        @Override
        public void run() {
            synchronized (sLock){
                System.out.println("学生持有了sLock锁,还需要获取tLock锁");
                synchronized (tLock){
                    System.out.println("学生更新成绩");
                }
            }
        }
    }

    public static void main(String[] args) {
        new Thread(new Teacher()).start();
        new Thread(new Student()).start();
    }
}

我们创建了两个线程Teacher和Student,这两个线程执行run方法需要获取两把锁
Teacher先获取tLock,再去获取sLock
Student先获取sLock,再去获取tLock
在Teacher的run方法中有句Thread.sleep(1000);是为了让Teacher让出cpu以保证Student获取sLock锁,从而形成死锁条件。

程序运行后,获取堆栈信息

3.线程一共有哪些状态呢(二)?_第3张图片

堆栈如下图
3.线程一共有哪些状态呢(二)?_第4张图片
可以看出Thread-1也就是Student线程已经获取了锁0x000000076bee60c8,在等待0x000000076bee60b8
Thread-0也就是Teacher获取了0x000000076bee60b8,在等待0x000000076bee60c8。
从而形成了死锁局面

你可能感兴趣的:(多线程)