Java中线程的状态、同步锁以及死锁详解

本文介绍了线程的六种状态及其转换,并通过实例演示了如何使用匿名内部类创建线程。此外,还深入探讨了线程同步的概念,包括同步锁、死锁等问题及解决方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

线程的状态

线程的六种状态
    1.新建状态(new 线程对象)
    2.运行状态(调用start方法)
    3.受阻塞状态(等待CPU的执行资源)
    4.休眠状态(调用了sleep(时间)方法)
    5.等待状态(调用了wait方法)
    6.死亡状态(run执行完毕)

线程的状态

匿名内部类

线程的第三种创建方式:
    匿名内部类方式:相当于创建了一个该类的子类对象
    new 父类或接口名(){
        重写父类方法
    };
    这里new出来的就是这个类的子类对象

示例代码:    
    class Test{
        public void fun() {
            System.out.println("我是父类的fun方法");
        }
    }
    public static void fun1() {
        // 创建Test类的子类对象
        Test test =  new Test() {
            // 重写父类方法
            @Override
            public void fun() {
                System.out.println("我是子类的fun方法");
            }
        };
        // 调用子类方法
        test.fun();
    }

接口:
    interface TestInter{
        public abstract void fun();
    }
    public static void fun2() {
        // 创建接口的实现类
        new TestInter() {

            @Override
            public void fun() {
                System.out.println("我是实现类的fun方法");
            }
        }.fun();
    }

需求:利用匿名内部类方式给TreeSet集合中的学生对象按年龄排序
        TreeSet<Student> set = new TreeSet<>(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return o1.getAge() - o2.getAge();
            }
        });
        set.add(new Student("sc", 18));
        set.add(new Student("kd", 19));
        set.add(new Student("kb", 17));
        for (Student student : set) {
            System.out.println(student);
        }

匿名内部类创建线程

继承:
        new Thread() {
            @Override
            public void run() {
                System.out.println("-----");
            }
        }.start();

接口:
        Runnable runnable = new Runnable() {

            @Override
            public void run() {
                System.out.println("|||||");
            }
        };
        new Thread(runnable).start();

合一起:
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("`````");
            }
        });
        thread.start();

线程休眠

sleep()的作用是让当前线程休眠,即当前线程会从运行状态进入到休眠状态。
sleep()会指定休眠时间

代码示例:
    public class Demo04 {
        public static void main(String[] args) throws InterruptedException {
            for (int i = 0; i < 100; i++) {
                // 线程休眠一秒 单位毫秒
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName() + i);
            }
        }
    }

    class SleepThread extends Thread{
        @Override
        public void run() {
            for (int i = 0; i < 50; i++) {
                /*
                 * 如果在子线程中出现异常只能try ... catch处理
                 * Thread类是Runnable接口的实现类
                 * 重写接口中的run方法
                 * 由于该方法没有抛出异常
                 * 所以所有Runnable接口的实现类(包括Thread类) 
                 * 都不能在run方法中抛出异常只能处理
                 */
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + i);
            }
        }
    }

同步锁(同步代码块)

同步锁:锁可以是任意对象,要保证锁的唯一

同步锁规则:
    线程遇到锁可以进入同步代码块(并且携带锁)
    当线程执行代码块中的代码后 把锁返还
    线程没有遇到锁 会在同步代码块外等待 遇到锁才能进

卖火车票问题:
    public class Demo {
        public static void main(String[] args) {
            Tickets t = new Tickets();
            // 创建3个线程 这3个线程会执行run方法(这条线程的任务)
            Thread t1 = new Thread(t);
            Thread t2 = new Thread(t);
            Thread t3 = new Thread(t);
            // 开启3个线程
            t1.start();
            t2.start();
            t3.start();
        }
    }

class  Tickets implements Runnable{
    // 声明50张票 保证票是共享数据 只new 一次该类对象
    private int tickets = 50;
    // 创建了对象锁 保证唯一
    private Object obj = new Object();
    // 卖票方法
    @Override
    public void run() {
        while (true) {
            // 锁只要保证是对象和唯一就可以 填this也可以
            synchronized (obj) {
                // 操作的共享数据的代码
                if (tickets > 0) {
                    // 让线程休眠
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    // 有票就卖
                    System.out.println(Thread.currentThread().getName() + "--" + tickets);
                    // 减少一张
                    tickets--;
                } else {
                    // 没票 结束循环
                    break;
                }
            }
            // 让线程让出CPU的资源
            Thread.yield();
        }
    }   
}

在方法中添加synchronized关键词 把方法变成 同步方法
class  Tickets1 implements Runnable{

    private int tickets = 50;
    // 创建了对象锁 保证唯一
    private Object obj = new Object();
    // 卖票方法
    @Override
    public void run() {
        while (true) {
            if (sellTickets()) {
                break;
            }
            // 让线程让出CPU的资源
            Thread.yield();
        }
    }
    // 操作共享数据的方法
    public synchronized boolean sellTickets() {

        // 静态方法的同步代码的锁可以使用本类 类名.class
        // public static boolean sellTickets() {
        //  synchronized (Object.class) {}

        // 操作的共享数据的代码
        if (tickets > 0) {
            // 让线程休眠
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 有票就卖
            System.out.println(Thread.currentThread().getName() + "--" + tickets);
            // 减少一张
            tickets--;
            return false;
        } else {
            // 没票 结束循环
            return true;
        }
    }
}

死锁

死锁:在编写多线程的时候,必须要注意资源的使用问题,如果两个或多个线程分别拥有不同的资源, 
而同时又需要对方释放资源才能继续运行时,就会发生死锁。比如如果线程1持有锁A并且想获得锁B,线程2持有锁B并且想获得锁A,那么这两个线程将永远等待下去,产生了死锁

模拟线程死锁:
    public class Demo07 {
        public static void main(String[] args) {
            DieLock dl = new DieLock();
            Thread t1 = new Thread(dl);
            Thread t2 = new Thread(dl);
            t1.start();
            t2.start();
        }
    }

    class LockA {
        // 私有构造方法
        private LockA() {
        }
        // 定义一个常量作为锁对象 不能修改(也不能创建)
        public static final LockA LOCK_A = new LockA();
    }

    class LockB {
        // 私有构造方法
        private LockB() {
        }
        // 定义一个常量作为锁对象 不能修改(也不能创建)
        public static final LockB LOCK_B = new LockB();
    }

    // 死锁
    class DieLock implements Runnable{  
        // 声明一个标记 一次是先A后B 一次是先B后A
        private boolean isTrue = true;
        @Override
        public void run() {
            // 死循环 增加死锁几率
            while (true) {
                // 按标记
                if (isTrue) {
                    // A锁到B锁
                    synchronized (LockA.LOCK_A) {
                        System.out.println("LOCK_A");
                        synchronized (LockB.LOCK_B) {
                            System.out.println("LOCK_B");
                        }
                    }
                } else {
                    // B锁到A锁
                    synchronized (LockB.LOCK_B) {
                        System.out.println("LOCK_B");
                        synchronized (LockA.LOCK_A) {
                            System.out.println("LOCK_A");
                        }
                    }
                }
                // 修改标记
                isTrue = !isTrue;
            }
        }   
    }

Lock接口

JDK1.5 锁 Lock接口
使用Lock锁
    lock.lock();
    try{
        写操作共享数据的代码
    } finally {
        lock.unlock();
    }

接口实现创建线程好处:
    1.避免直接继承Thread类的局限性(避免单继承)
    2.接口即插即用 减少类与类之间的联系(可以解耦)

使用接口Lock接口锁:
    public class Demo {
        public static void main(String[] args) {
            Tickets3 tickets3 = new Tickets3();
            // 创建3条线程 这条线程会执行 run方法(这条线程的任务)
            Thread t1 = new Thread(tickets3);
            Thread t2 = new Thread(tickets3);
            Thread t3 = new Thread(tickets3);
            // 开启3个线程
            t1.start();
            t2.start();
            t3.start();
        }
    }

    class Tickets3 implements Runnable{

        private int tickets = 50;
        // 声明锁对象
        private ReentrantLock lock = new ReentrantLock();

        @Override
        public void run() {
            while (true) {
                // 加锁
                lock.lock();
                try {
                    // 锁住操作共享数据的代码
                    if (tickets > 0) {
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() + "--" + tickets);
                        tickets--;
                    } else {
                        break;
                    }
                } finally {
                    // 解锁
                    lock.unlock();
                }
                Thread.yield();
            }
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值