Java面向对象之线程相关概念 和 线程基本使用

1、多线程基础

1.1、线程相关概念
1.1.1、程序(program)

在这里插入图片描述

1.1.2、进程

在这里插入图片描述

1.1.3、线程

在这里插入图片描述

1.1.4、其他相关概念

在这里插入图片描述
在这里插入图片描述

1.2、线程基本使用
1.2.1、创建线程的两种方式

在这里插入图片描述

1.2.2、线程应用方式1 - 继承 Thread 类

在这里插入图片描述

package threaduse;

public class Thread01 {
    public static void main(String[] args) throws InterruptedException {
        // 创建 Cat 对象, 可以当做线程使用
        Cat cat = new Cat();
        // 源码
        /**
         (1)
         public synchronized void start() {
         start0();
         }
         (2)
         start0() 是本地方法, 是 JVM 调用, 底层是 c/c++实现
         真正实现多线程的效果, 是 start0(), 而不是 run
         private native void start0();
         */
        cat.start();  // 启动线程 -> 最终会执行 cat 的 run 方法
        // cat.run();
        // run 方法就是一个普通的方法, 没有真正的启动一个线程, 就会把 run 方法执行完毕, 才向下执行
        // 说明: 当 main 线程启动一个子线程 Thread-0, 主线程不会阻塞, 会继续执行
        // 这时 主线程和子线程是交替执行
        System.out.println("主线程继续执行" + Thread.currentThread().getName());  // 名字 main
        for (int i = 0; i < 60; i++) {
            System.out.println("主线程i=" + i);
            // 让主线程休眠
            Thread.sleep(1000);
        }
    }
}

// 1. 当一个类继承了 Thread 类, 该类就可以当做线程使用
// 2. 我们会重写 run 方法, 写上自己的业务代码
// 3. run Thread 类 实现了 Runnable 接口的 run 方法
/*
    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }
*/

class Cat extends Thread {
    int times = 0;

    @Override
    public void run() {  // 重写 run 方法, 写上自己的业务逻辑
        while (true) {
            // 该线程每隔 1 秒, 在控制台输出 “喵喵, 我是小猫咪”
            System.out.println("喵喵, 我是小猫咪 " + (++times) + " 线程名=" + Thread.currentThread().getName());
            // 让该线程休眠 1 秒 ctrl+alt+t
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (times == 80) break;  // 当 times 到 80, 退出 while, 这时线程也就退出
        }
    }
}

在这里插入图片描述

1.2.3、线程应用2 - 实现 Runnable 接口

在这里插入图片描述
在这里插入图片描述

package threaduse;

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();

        Tiger tiger = new Tiger();
        ThreadProxy threadProxy = new ThreadProxy(tiger);
        threadProxy.start();
    }
}

class Animal {
}

class Tiger extends Animal implements Runnable {

    @Override
    public void run() {
        System.out.println("老虎嗷嗷叫...");
    }
}

// 线程代理类, 模拟了一个极简的 Thread 类
class ThreadProxy implements Runnable {  // 你可以把 Proxy 类当做 ThreadProxy
    private Runnable target = null;  // 属性, 类型是 Runnable

    @Override
    public void run() {
        if (target != null) {
            target.run();  // 动态绑定(运行类型 Tiger)
        }
    }

    public ThreadProxy(Runnable target) {
        this.target = target;
    }

    public void start() {
        start0();  // 这个方法时真正实现多线程方法
    }

    public void start0() {
        run();
    }
}

class Dog implements Runnable {  // 通过实现 Runnable 接口, 开发线程
    int count = 0;

    @Override
    public void run() {  // 普通方法
        while (true) {
            System.out.println("小狗汪汪叫..hi " + (++count) + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (count == 10) break;
        }
    }
}
1.2.4、线程使用应用案例 - 多线程执行

在这里插入图片描述

package threaduse;

public class Thread03 {
    public static void main(String[] args) {
        T1 t1 = new T1();
        T2 t2 = new T2();
        Thread thread1 = new Thread(t1);
        Thread thread2 = new Thread(t2);
        thread1.start();
        thread2.start();
    }
}

class T1 implements Runnable {
    int count = 0;

    @Override
    public void run() {
        while (true) {
            // 每隔 1 秒输出 “hello,world”, 输出 10次
            System.out.println("hello,world " + (++count));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (count == 10) break;
        }
    }
}

class T2 implements Runnable {
    int count = 0;

    @Override
    public void run() {
        while (true) {
            // 每隔 1 秒输出 “hi”, 输出 5 次
            System.out.println("hi " + (++count));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (count == 5) break;
        }
    }
}
1.2.5、线程如何理解

在这里插入图片描述
在这里插入图片描述

1.2.6、继承 Thread vs 实现 Runnable 的区别

在这里插入图片描述
在这里插入图片描述

package threaduse;

/**
 * 使用多线程, 模拟三个窗口同时售票 100 张
 */
public class SellTicket {
    public static void main(String[] args) {
        // 测试

        System.out.println("=== 继承Thread方式来售票 ===");
        SellTicket01 sellTicket01 = new SellTicket01();
        SellTicket01 sellTicket02 = new SellTicket01();
        SellTicket01 sellTicket03 = new SellTicket01();
        // 这里我们会出现超卖
        sellTicket01.start();  // 启动售票线程
        sellTicket02.start();  // 启动售票线程
        sellTicket03.start();  // 启动售票线程


        System.out.println("=== 使用实现接口方式来售票 ===");
        SellTicket02 sellTicket021 = new SellTicket02();
        new Thread(sellTicket021).start();  // 第 1 个线程-窗口
        new Thread(sellTicket021).start();  // 第 2 个线程-窗口
        new Thread(sellTicket021).start();  // 第 3 个线程-窗口

        // 结论: 这两种方式都会出现超卖的现象
    }
}

class SellTicket01 extends Thread {
    private static int ticketNum = 100;  // 让多个线程共享 ticketNum

    @Override
    public void run() {
        while (true) {
            if (ticketNum <= 0) {
                System.out.println("售票结束...");
                break;
            }

            // 休眠50毫秒, 模拟
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票" + " 剩余票数=" + (--ticketNum));
        }
    }
}

// 实现接口方式
class SellTicket02 implements Runnable {
    private int ticketNum = 100;  // 让多个线程共享 ticketNum

    @Override
    public void run() {
        while (true) {
            if (ticketNum <= 0) {
                System.out.println("售票结束...");
                break;
            }

            // 休眠50毫秒, 模拟
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票" + " 剩余票数=" + (--ticketNum));
        }
    }
}

结论:这两种方式都会出现超卖的现象

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值