线程使用

SOBER大约 3 分钟

线程使用

创建线程的两种方式

  1. 继承 Thread 类,重写 run方法
  2. 实现 Runnable 接口,重写 run 方法

示例1 - 继承 Thread 类

  1. 请编写程序,开启一个线程, 该线程每隔1秒。在控制台输出 “喵喵, 我是小猫咪”
  2. 对上题改进:当输出 80 次 喵喵, 我是小猫咪,结束该线程
  3. 使用 JConsole 监控线程执行情况,并画出程序示意图!
package commonThread;

public class Thread01 {
    public static void main(String[] args) throws InterruptedException {
        // 创建 Cart 对象,可以当做线程使用
        Cart cart = new Cart();
        cart.start(); // 启动线程->最终会执行cat的run方法
        // cart.run(); //run方法就是一个普通的方法,没有真正的启动一个线程,就会把run方法执行完毕,才向下执行
        /**
         * 说明
         * 当main线程启动一个子线程 Thread-0,主线程不会阻塞,会继续执行
         */
        System.out.println("主线程继续执行" + Thread.currentThread().getName());
        for (int i = 0; i < 800; i++){
            System.out.println("主线程 i = " + i);
            Thread.sleep(1000);
        }
    }
}

/**
 * 1. 当一个类继承了 Thread 类,该类就可以当做线程使用
 * 2. 我们会重写 run 方法,写上自己的业务代码
 * 3. Thread 类本身没有 run 方法 是 Thread 类 实现了 Runnable 接口的 run 方法
 */
class Cart extends Thread { // 重写 run 方法,写上自己的业务逻辑
    int times = 0;
    @Override
    public void run() {
        while (true) {
            // 该线程每隔1秒。在控制台输出“喵喵,我是小猫咪”
            System.out.println("喵喵,我是小猫咪" + (++times) + " 线程名:" + Thread.currentThread().getName());

            try {
                // 让该线程休眠1秒 快捷键 ctrl + alt + t
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            if(times == 800) {
                break;
            }
        }
    }
}

打开终端,输入JConsole,回车,找到对应的线程名

示意图

示例2 - 实现 Runnable 接口

说明

  1. java 是单继承的,在某些情况下一个类可能已经继承了某个父类,这时在用继承Thread类方法来创建线程显然不可能了。
  2. java 设计者们提供了另外一个方式创建线程,就是通过实现 Runnable 接口来创建线程
package commonThread;

public class Thread02 {
    public static void main(String[] args) {
        Dog dog = new Dog();
        // dog.start(); 这里不能调用 start
        // 创建 Thread 对象,把 dog 对象(实现Runnable) 放入 Thread
        Thread thread = new Thread(dog); // 这里底层使用了设计模式[代理模式]
        thread.start();
    }
}

class Dog implements Runnable {
    int count = 0;

    @Override
    public void run(){

        try {
            while (true) {
                System.out.println("小狗" + (++count) + Thread.currentThread().getName());
                Thread.sleep(1000);
                if(count == 80) {
                    break;
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

案例3 - 多线程执行

请编写一个程序,创建两个线程,一个线程每隔 1秒 输出 “hello,world”,输出 10次,退出,一个线程每隔 1秒 输出 “hi” ,输出 5次退出

package commonThread;

public class Thread03 {
    public static void main(String[] args) {
        Dog1 dog1 = new Dog1();
        Dog1 dog2 = new Dog1();
        Thread thread1 = new Thread(dog1);
        Thread thread2 = new Thread(dog2);
        thread1.start();
        thread2.start();
    }
}

class Dog1 implements Runnable {
    int count = 0;
    @Override
    public void run(){
        while(true) {
            try {
                System.out.println("Dog1 线程" + (++count) + Thread.currentThread().getName());
                Thread.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

class Dog2 implements Runnable {
    int count = 0;
    @Override
    public void run(){
        while(true) {
            try {
                System.out.println("Dog2 线程" + (++count) + Thread.currentThread().getName());
                Thread.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

继承 Thread VS 实现 Rlnnable 的区别

  1. 从 Java 的设计来看,通过继承 Thread 或者实现 Runnable 接口来创建线程本质上没有区别,从 Jdk 帮助文档我们可以看到 Thread 类本身就实现了 Runnable 接口 start() ---> start0()
  2. 实现 Runnable 接口方式更加适合多个线程共享一个资源的情况,并且避免了单继承的限制

线程终止

说明

  1. 当线程完成任务后,会自动退出
  2. 还可以通过使用变量来控制 run 方法退出的方式停止线程,即通知方式

示例

需求: 启动一个线程 t,要求在 main 线程中去停止线程 t, 请编程实现,

package commonThread;

public class Thread04 {
    public static void main(String[] args) throws InterruptedException {
        T t = new T();
        Thread thread = new Thread(t);
        thread.start();
        Thread.sleep(2000);
        t.setLoop(false);
    }
}

class T extends Thread {
    int count = 0;
    private boolean loop = true;

    @Override
    public void run() {
        while(loop) {
            System.out.println("主线程" + (++count));
        }
    }

    public void setLoop(boolean loop) {
        this.loop = loop;
    }
}