线程创建&启动&停止
线程啊是个好东西,但是平时工作很少自己创建线程,所以一些基础的操作可能就不容易记起来,这篇文章常看看有益身心健康
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异常 进行线程结束
可能还有其他方式 大多数是基于标志位的
欢迎关注公众号: