写点什么

话说 线程创建 & 启动 & 停止

发布于: 2021 年 04 月 05 日
话说 线程创建&启动&停止

线程啊是个好东西,但是平时工作很少自己创建线程,所以一些基础的操作可能就不容易记起来,这篇文章常看看有益身心健康

1. 创建
public class TestDeamon {    public static void main(String[] args) {        // lambda 表达式        Thread t1 = new Thread(()->System.out.println("这是一个线程01!"));        Thread t2 = new Thread(()->{            System.out.println("这是一个线程02!");        });        // 匿名内部类        Thread t3 = new Thread(){            @Override            public void run() {                System.out.println("这是一个线程03!");            }        };        // 继承Thread        Thread t4 =new MyThread04();
// 实现Runnable 参数是Runnable Thread t5 = new Thread(new MyRunnable());
// 时效内 // 启动线程 t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); }}
/** * 继承Thread * public class Thread implements Runnable * thread是实现了Runnable接口 */class MyThread04 extends Thread{ @Override public void run() { System.out.println("这是一个线程04!"); }}
/** * 实现Runnable */class MyRunnable implements Runnable{ @Override public void run() { System.out.println("这是一个线程05!"); }}
复制代码
2. 启动
// 启动线程t1.start();t2.start();t3.start();t4.start();t5.start();输出:这是一个线程01!这是一个线程02!这是一个线程03!这是一个线程04!这是一个线程05!
复制代码


线程启动之后就会执行 run 方法

3. 停止线程/中断

3.1. 线程执行完 自己结束


执行完 for 循环 自动结束


// lambda 表达式        Thread t1 = new Thread(()->{            for (int i = 0; i < 10; i++) {                try{                    Thread.sleep(1000);                    System.out.println("===");                } catch (Exception e) {                    e.printStackTrace();                }            }        });        t1.start();
复制代码


3.2. stop 被废弃了


stop 已经被废弃,stop 太粗暴,不温柔,所以没人喜欢..


 // lambda 表达式Thread t1 = new Thread(()->{    for (;;) {        try{            Thread.sleep(1000);            System.out.println("===");        } catch (Exception e) {            e.printStackTrace();        }    }});t1.start();// 10秒后 停止Thread.sleep(10000);// 停止t1.stop();
复制代码


很容易产生数据不一致 因为某一个事务或者一块代码没执行完的时候 就有可能被干掉


举个例子:


// lambda 表达式Thread t1 = new Thread(()->{    System.out.println("对象去洗澡了");    try{        System.out.println("钻被窝等着...");        Thread.sleep(10000);        System.out.println("洗白白 开小会");    } catch (Exception e) {        e.printStackTrace();    }});
t1.start();// 10秒后 停止Thread.sleep(5000);// 停止t1.stop();
结果:对象去洗澡了钻被窝等着... 可以看到哈,你等了半天,还没开始开小会就被打断了 。。
复制代码


3.3 suspend resume 被废弃了


suspend 让线程暂停


resume 让暂停的线程继续执行


suspend 容易产生死锁等问题 如果忘记 resume 或者 resume 异常 那如果 suspend 的线程持有锁的话,就死锁了


public class TestDeamon03 {    // 锁  表示对象    public static Object obj = new Object();    public static void main(String[] args) throws InterruptedException {
// lambda 表达式 Thread t1 = new Thread(()->{ synchronized (obj){ try { System.out.println("我出去打工了 留对象在家"); Thread.sleep(10000); System.out.println("我回来了 娶我对象 "); } catch (Exception e) { e.printStackTrace(); } } });
t1.start(); // 2秒后 暂停 Thread.sleep(2000); // 暂停 t1.suspend(); Thread.sleep(2000); // 恢复 resumeObj(t1); }
// resume 模拟异常 static void resumeObj(Thread t){ int i = 1/0; t.resume(); }}
复制代码


你找了个对象,把人家放家里,说打工 1 年回来娶,然后你回家途中找了个别人,一起幸福生活了,你对象在家...


被你占用,你又不通知、不释放


3.4 volatile 结束


volatile(保证内存可见)修饰一个变量 时间可能控制不是很精确 因为 volatile 修改了之后刷新到内存 在另一个线程读取到 还是需要时间的 虽然很快 但是一般的情况 都没什么问题


public class TestDeamon04 {    static volatile boolean flag = true;    public static void main(String[] args) throws InterruptedException {        // lambda 表达式        Thread t1 = new Thread(()->{            int count =0;            // flag == true 循环   flag==false 停止循环 也就结束线程了            while (flag) {                try {                    Thread.sleep(1);                    count++;                } catch (Exception e){                    e.printStackTrace();                }            }            System.out.println("count:"+count);        });
t1.start(); // 1秒后 停止 Thread.sleep(1000); flag = false; }}
多次输出结果: 505、525、507、512 可以看到每次输出结果是不确定的 ,这种方式只能保证到达某个条件了就停止线程 但是不能控制线程准确点停止 比如你想让一个线程循环100次就停止 很难准确控制
复制代码


3.5 interrupt 结束


也算标志位 但是比 volatile 高级一点 比如 sleep、wait 等操作会被中断


// lambda 表达式final Thread t1 = new Thread(()->{    int count =0;    //    while (!Thread.interrupted()) {        try {            count++;        } catch (Exception e){            e.printStackTrace();        }    }    System.out.println("count:"+count);});
t1.start();// 1秒后 停止Thread.sleep(1000);t1.interrupt();
复制代码


中断 sleep 测试:interrupt 会中断 sleep 在异常捕获里边 break 就行了 而标志位 flag 是无法做到的


public class TestDeamon06 {    static volatile boolean flag = true;    public static void main(String[] args) throws InterruptedException {        // lambda 表达式        final Thread t1 = new Thread(()->{            //            while (!Thread.interrupted()) {                try {                    Thread.sleep(20000000);                } catch (Exception e){                    break;                }            }            System.out.println("interrupted 结束 ");        });
// lambda 表达式 final Thread t2 = new Thread(()->{ while (flag) { try { Thread.sleep(20000000); } catch (Exception e){ break; } } System.out.println("volatile-结束"); });
t1.start(); t2.start(); // 1秒后 停止 Thread.sleep(1000); t1.interrupt(); flag = false; }}
复制代码


总结:


stop 、suspend resume 已废弃


volatile 标志位 无法中断 sleep wait 等操作


interrupt 相当于标志位但是可以中断 sleep wait 等操作 捕获 InterruptedException 异常 进行线程结束


可能还有其他方式 大多数是基于标志位的


欢迎关注公众号:


用户头像

还未添加个人签名 2018.03.28 加入

还未添加个人简介

评论

发布
暂无评论
话说 线程创建&启动&停止