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

线程创建&启动&停止

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

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异常 进行线程结束

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

有问题可以留言哦,或者公众号留言(回复快):
image

你可能感兴趣的:(面试java线程)