java多线程——线程的创建(Thread类、Runable接口、线程的优先级)

三种创建方式

基于什么创建创建的方式
Thread继承Thread
Runnable接口实现Runnable接口
callable接口实现callable接口

通过Thread类创建

步骤

  • 自定义线程类继承Thread
  • 重写run()方法,编写线程执行体(当成main()方法用)
  • 创建线程对象,调用start()方法启动线程

案例

  • 创建两个线程,其中一个线程打印100以内的偶数,另一个线程打印100以内的奇数
    //主方法
    public class Demo01 {
        public static void main(String[] args) {
            Thread1 thread1 = new Thread1();
            Thread2 thread2 = new Thread2();
    
            thread1.start();
            thread2.start();
        }
    }
    
    //100以内的偶数
    class Thread1 extends Thread {
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                if (i%2==0){
                    System.out.println(Thread.currentThread().getName() + ":" + i);
                }
            }
        }
    }
    
    //100以内的奇数
    class Thread2 extends Thread {
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                if (i%2!=0){
                    System.out.println(Thread.currentThread().getName() + ":" + i);
                }
            }
        }
    }
    
  • 也可以使用匿名内部类的方法来实现(线程用过以后就不再用了)
    public class Demo02 {
        public static void main(String[] args) {
            //打印0~100内的偶数
            new Thread(){
                @Override
                public void run() {
                    for (int i = 0; i < 100; i++) {
                        if (i%2==0){
                            System.out.println(Thread.currentThread().getName() + ":" + i);
                        }
                    }
                }
            }.start();
            //打印0~100内的奇数
            new Thread(){
                @Override
                public void run() {
                    for (int i = 0; i < 100; i++) {
                        if (i%2!=0){
                            System.out.println(Thread.currentThread().getName() + ":" + i);
                        }
                    }
                }
            }.start();
        }
    }
    
  • 三个窗口同时卖票,票数总共为100张(注意票数应该是静态变量,否则就是没创建一个对象,该对象就有100张票)
    public class Test {
        public static void main(String[] args) {
            Window w1 = new Window("窗口 1 ");
            Window w2 = new Window("窗口 2 ");
            Window w3 = new Window("窗口 3 ");
    
            w1.start();
            w2.start();
            w3.start();
        }
    }
    
    class Window extends Thread{
        //这里票的数量应该是静态变量,否则每个对象创建后都有100张票,而不是总共100张票
        private static int tickets = 100;
    
        public Window(String name) {
            super(name);
        }
    
        @Override
        public void run() {
            while (tickets > 0){
                tickets--;
                System.out.println(getName() + "卖出了一张票,剩余票数:" + tickets);
            }
        }
    }
    
    • 注意:这里存在一个线程安全问题未解决,后面将会讲到。如下图所示,刚开始三个线程启动的时候,读取的票数都是100张。
      在这里插入图片描述

注意的问题

  • start()方法的作用:通过调用自己写的线程类对象的start()方法,来启动该线程,并调用该线程的run()方法
  • 不能通过直接调用run()方法的方式启动线程
  • 不可以让已经start()的线程再次star()来同时跑两个线程。可以通过新建一个该线程类的对象,然后在对新建的对象start()

Thread类中常用的方法

  • start():启动当前线程;调用当前线程的run()方法
  • run():通常需要重写Thread类中的此方法,将创建线程需要执行的操作声明在此方法中(当做main()使用)
  • currentThread():静态方法,返回执行当前代码的线程
  • getName():获取当前线程的名字
  • setName(String name):设置当前线程的名字
  • yield():释放当前CPU的执行权(但也有可能下一刻的执行权又回到了当前线程,主控权还是在CPU手上)
  • join():在线程a中调用线程bjoin(),此时线程a就进入阻塞状态,直到线程b完全执行完之后,线程a在结束阻塞状态
  • stop():当执行此方法时,强制结束当前线程(已停用
  • sleep(int millitime):让当前线程“睡眠”指定的millitime毫秒。在指定的millitime毫秒时间内,当前进程是阻塞状态
  • isAlive():判断当前线程是否存活(线程执行完之前都是存活的)

案例

  • 同样是上面的三个窗口买票的问题,同样是100张票,但使用这种创建方法,tickets可以不使用静态变量
    在这里插入图片描述

通过实现Runnable接口来创建线程

创建步骤

  • 创建一个实现了Runnable接口的类
  • 实现类去实现Runnable接口中的抽象方法:run()
  • 创建实现类的对象
  • 将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
  • 通过Thread类的对象调用start()
    • 这里的start()首先启动了当前的线程,然后调用了Runnable类型的target的run()
      在这里插入图片描述

继承Thread类和实现Runnable接口两种方式比较

  • 开发中,优先选择实现Runnable接口的方式创建线程
    • 原因:
      • 实现Runnable接口的方式没有类的单继承性的局限性(一个类只能继承一个父类,继承了Thread类就不能在继承其他类了)
      • 实现Runnable接口的方式更适合来处理多个线程之间有共享数据的情况
  • 联系:Thread类本身也实现了Runnable接口
    在这里插入图片描述
  • 相同点:两种方式都需要重写run()方法,将线程要执行的逻辑声明在run()方法中

线程的优先级设置

  • 调度策略
    • 对于同优先级的线程,组成先入先出队列(先到先服务),使用时间片策略
    • 对于高优先级,使用优先调度的抢占式模式
  • 线程的优先级分为1~10十个档,其中:
    • NORM_PRIORITY:5 —— 普通优先级,即默认的优先级
    • MAX_PRIORITY:10 —— 最高优先级
    • MIN_PRIORITY:1 —— 最低优先级
  • getPriority():获取线程的优先级
  • setPriority(int p):设置线程的优先级
  • 注意:高优先级的线程要抢占低优先级线程CPU的执行权。但是只是从概率上来讲,高优先级的线程高概率的情况下被执行。并不意味着只有当高优先级的线程被执行完以后,低优先级的线程才会被执行。

总结

  • 线程开启后不一定立即执行,有CPU进行调度(如果只有一个CPU,主线程和创建的线程会交替执行)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值