Java线程生命周期和锁的简单使用

本文介绍了java线程的生命周期,Synchronized的几个方法简单的使用。

线程生命周期

  • 初始状态(New)

    New Thread之后,
     

  • 就绪状态(Ready)

    表示获取到了Cpu的执行时间片,也就是cpu的执行权,等待开始执行。
     

  • 运行状态(Runable)

    执行start之后,开始运行。
     

  • 阻塞状态(Blocked)

    在进入synchronized的临界区或者Lock的临界区,等待获取监视器(monitor)锁,线程会进入同步队列(SynchronizedQueue)中。
     

  • 等待状态:(Waiting)

    在执行await(),wait(),jion(),LockSupport.park()方法进入等待状态;
     

  • 等待超时状态

    在执行Object.await(time), Object.wait(time), Object.sellp(time), LockSupport.parkUntil,lockSupport.parkNanos 进入等待超时状态。
     

  • 终止状态

    线程执行完毕或者执行了Thread.interrupt() / Thread.stop(),不建议使用的Thread.stop() 因为 Thread.stop是直接强行结束,不会释放资源

  • 配图

    线程生命周期.png

锁的几个简单方法

  • wait 和 notify/notifyAll

    解释

    wait: 将线程状态置位 '等待状态',进入等待队列等待。
    notify/notifyAll: notify是随机唤醒一个线程进入 '同步队列',notifyAll是唤醒全部被监视器锁wait的线程进入 '同步队列',等待获取监视器锁后继续执行。

    提示:wait,notify/notifyAll都需要在获取到监视器所(monitor)后才可以进行操作。

    代码
    public class WaitAndNotifyTest {
    
        private static Object obj = new Object();
    
        public static void main(String[] args) {
            // 创建线程 thread1
            Thread thread1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println(Thread.currentThread().getName() + "   begin wait...");
                        synchronized (obj) {
                            obj.wait();
                        }
                        System.out.println(Thread.currentThread().getName() + "   end wait...");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }, "thread1");
    
            // 创建线程 thread2
            Thread thread2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println(Thread.currentThread().getName() + "   begin wait...");
                        synchronized (obj) {
                            obj.wait();
                        }
                        System.out.println(Thread.currentThread().getName() + "   end wait...");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }, "thread2");
    
    
    
            // 启动
            thread1.start();
            thread2.start();
    
            try {
                // 睡眠一秒
                Thread.sleep(1000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            // 下面我们加上 obj.notify() 就会先输出 begin wait  然后sellp 10秒,执行obj.notify() 唤醒 thread1 线程 , 输出end wait
            // obj 上可能会存在wait 多个线程, notify唤醒是随机的,不一定能唤醒哪一个线程
            // 如果调用 notify 的线程未获取 对象锁,在调用 notify 的时候会抛出 java.lang.IllegalMonitorStateException 异常
            synchronized (obj) {
                // 唤醒 使用呢 obj 调用 wait 方法的其中一个线程 (随机)
                obj.notify();
                // 唤醒 使用呢 obj 调用 wait 方法的所有线程
                obj.notifyAll();
            }
        }
    }
    
    执行结果:
    thread2   begin wait...
    thread1   begin wait...
    thread1   end wait...
    thread2   end wait...
    
  • await,signal/signalAll

    解释

    await,signal/signalAll方法是Lock Condition的方法,语义和Object的wait,notify/notifyAll是完全相同的。

    代码
    /**
     * @Auther: lantao
     * @Date: 2019-04-15 14:49
     * @Company:
     * @maill:
     * @Description: Condition 条件 有 singal signalAll 和 await 方法 和Object 的 notify notifyAll 和 wait 是一个意思同样会释放锁  执行singal和notify的时候也需要在等待获取锁
     */
            public class LockCondition {
    
                public static ReentrantLock lock = new ReentrantLock();
    
                public static Condition a = lock.newCondition();
    
                public static void main(String[] args) throws InterruptedException {
                    Runnable runnable = () -> {
                        try {
                            lock.lock();
                            System.out.println(Thread.currentThread().getName());
                            System.out.println("1");
                            a.await();
    
                            System.out.println(Thread.currentThread().getName() + "被唤醒了");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }finally {
                            lock.unlock();
                        }
                    };
    
                    Runnable runnable1 = () -> {
                        try {
                            lock.lock();
                            System.out.println("线程" +Thread.currentThread().getName() + "开始执行sinal");
                            a.signalAll();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }finally {
                            lock.unlock();
                        }
                    };
    
                    new Thread(runnable,"Thread1").start();
                    new Thread(runnable,"Thread2").start();
                    Thread.sleep(100);
                    new Thread(runnable1,"Thread3").start();
                }
            }
    
    执行结果:
    Thread1
    Thread2
    线程Thread3开始执行sinal
    Thread1被唤醒了
    Thread2被唤醒了
    
  • Join 和 Join(time)

    解释

    等待调用Join的线程执行完成后再继续执行,或者等待时间超过了超时时间继续执行

    代码
    /**
     * @Auther: lantao
     * @Date:
     * @Company:
     * @maill:
     * @Description: Join 核心是等待指定线程运行完后再继续运行  Join(time) 就是等待线程执行的一个超时时间 超过了就继续执行了
     */
            public class JoinTest {
                public static void main(String[] args) throws InterruptedException {
                    Thread thread1 = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            System.out.println("1");
                            try {
                                Thread.sleep(2000L);
                                System.out.println("正常完成");
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            System.out.println("2");
                        }
                    });
    
                    thread1.start();
    
                    // 执行 jion 等待线程 thread1 执行完后再继续执行
                    thread1.join();
    //        thread1.join(1000);
    
                    // 这样最终执行的顺序是 1 2 3  如果不增加 thread1.join() 结果可能是 312 也可能是 132
                    // Join 核心是等待指定线程运行完后再继续运行
                    System.out.println("3");
                }
            }
    
    执行结果:
    1
    正常完成
    2
    3
    
  • yield

    解释

    yeid 方法的核心是让出 cpu 时间片 ,也就是cpu执行权,线程会直接进入就绪状态,线程调度器会从线程就绪队列里获取一个线程优先级最高的线程来执行,当然也有可能直接会去到刚刚让出cpu执行权的线程,继续执行yield 后续的代码。

    代码
    /**
     * @Auther: lantao
     * @Date: 2019-03-25 17:20
     * @Company:
     * @maill:
     * @Description:
     */
            public class YieldTest {
    
                private static Object obj = new Object();
    
    
                public static void main(String[] args) {
                    Thread thread1 = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            for (int i = 0; i <= 5; i++) {
    
                                if (0 / 5 == i) {
                                    System.out.println(Thread.currentThread().getName() + "   开始执行 yield ");
                                    Thread.yield();
                                    System.out.println("trhead1");
                                }
                            }
                        }
                    }, "thread1");
                    Thread thread2 = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            for (int i = 0; i <= 5; i++) {
                                if (0 / 5 == i) {
                                    System.out.println(Thread.currentThread().getName() + "   开始执行 yield ");
                                    Thread.yield();
                                    System.out.println("trhead2");
                                }
                            }
                        }
                    }, "thread2");
                    Thread thread3 = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            for (int i = 0; i <= 5; i++) {
                                if (0 / 5 == i) {
                                    System.out.println(Thread.currentThread().getName() + "   开始执行 yield ");
                                    Thread.yield();
                                    System.out.println("trhead3");
                                }
                            }
    
                        }
                    }, "thread3");
    
                    // 执行三个线程, 正常当运行到yield 是 就会让出cpu执行权,线程到 就绪状态,线程调度器会从 线程就绪队列里获取一个线程优先级最高的线程来执行,
                    // 当然也有可能直接会去到刚刚让出cpu的线程,继续执行yield 后续的代码
                    thread1.start();
                    thread3.start();
                    thread2.start();
    
                }
            }
    
    执行结果:
    
    thread1   开始执行 yield
    thread2   开始执行 yield
    thread3   开始执行 yield
            trhead2
    trhead1
    trhead3
    
  • interrupt 和 stop

    解释

    interrupt和stop都代表中断线程,区别是 interrupt 会释放资源而stop不会,interrupt也不会立马就中断;说道interrupt就得说一下isInterrupted方法,他是判断线程中断标志的,如果线程A执行了线程B的interrupt方法,线程B在自己的线程中也可以使用 isInterrupted 方法判断自己的中断标志。
     
    注意:在使用 interrupt方法时,如果线程在sleep wait wait(time)状态, 抛出InterruptedException异常后会清除 isInterrupted 方法获取的中断标志位,反之则不会

    代码
    /**
     * @Auther: lantao
     * @Date: 2019-04-17 17:18
     * @Company:
     * @maill:
     * @Description: 在使用 interrupt方法是,如果线程咋sleep wait wait(time) 在抛出InterruptedException异常后会 清除 isInterrupted 方法获取的标志位 其他则不会
     */
            public class InterruptTest {
                public static void main(String[] args) throws InterruptedException {
                    Thread thread1 = new Thread(() -> {
                        while (true) {}
                    }, "循环线程");
    
                    Thread thread2 = new Thread(() -> {
                        while (true) {
                            try {
                                Thread.sleep(200);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }, "睡眠线程");
    
                    Thread thread3 = new Thread(() -> {
                        Object o = new Object();
                        while (true) {
                            synchronized (o){
                                try {
                                    o.wait();
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    }, "等待线程");
    
                    thread1.start();
                    thread2.start();
                    thread3.start();
                    Thread.sleep(500);
    
                    thread1.interrupt();
                    thread2.interrupt();
                    thread3.interrupt();
                    Thread.sleep(500);
                    System.out.println("循环线程isInteryupt is " + thread1.isInterrupted());
                    System.out.println("睡眠线程isInteryupt is " + thread2.isInterrupted());
                    System.out.println("等待线程isInteryupt is " + thread3.isInterrupted());
    
    
                }
            }
    
    执行结果:
    
    java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at com.com.concurrenncy.InterruptTest.lambda$main$1(InterruptTest.java:20)
    at java.lang.Thread.run(Thread.java:748)
    java.lang.InterruptedException
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Object.java:502)
    at com.com.concurrenncy.InterruptTest.lambda$main$2(InterruptTest.java:32)
    at java.lang.Thread.run(Thread.java:748)
    循环线程isInteryupt is true
    睡眠线程isInteryupt is false
    等待线程isInteryupt is false
    

博客地址:https://lantaoblog.site

image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343