两种方式的比较:
1.优先选择实现Runnable接口
原因:1.实现的方式没有类得单继承性的局限性
2.实现的方式更适合来处理多个线程有共享数据的情况

2.联系:
两种方式都要重写run()方法,将要处理的逻辑写在run()方法中

第一种方式:

package com.sinosoft;

/**
 * @author lj
 * @Create 2020-11-28-12:11
 * @description 多线程的创建,方式一:继承于Thread类
 *
 *
 *  * eg: 遍历100以内的所有的偶数
 * 1.创建一个继承于Thread类的子类
 * 2.重写Thread类的run()方法  ---->讲此线程执行的操作声明在run()方法中
 * 3.创建Thread类的子类的对象
 * 4.通过此对象调用start()---->1.使得我们创建的线程开始执行 2.java虚拟机调用当前的run()方法
 * 5.getName()
 * 6.setName()
 * 7. yield();//释放当前cpu执行权
 * 8.join() :在线程a中调用线程b的join(),此时线程a就进入了阻塞状态,直到线程b执行完之后,线程a才结束阻塞状态
 * 9.sleep(毫秒数):指定的时间之内当前线程是阻塞状态
 * 10.isAlive():判断当前线程是否还存活
 *
 *    线程的优先级:
 *    1.MAX_PRIORITY  10
 *    2.MIN_PRIORITY   1
 *    3.NORM_PRIORITY   5
 *
 *  如何获取和设置当前线程的优先级:
 *  getPriority():获取线程优先级
 *  setPriority(int ):设置线程的优先级p
 *
 *  说明:优先级高的会抢占优先级低的CPU资源,但是并不代表优先级高的会先执行完

 */
// 1.创建一个继承于Thread类的子类
class MyThread extends Thread {
    //2.重写Thread类的run()方法
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if (i % 2 == 0) {
                System.out.println(Thread.currentThread().getName() + ":" + Thread.currentThread().getPriority() +":" +i);
            }

//            if (i % 20 == 0 ){
//              yield();//释放当前cpu执行权
//            }
        }


    }
}

public class ThreadTest {

    public static void main(String[] args) {  //主线程做的事情在main方法里面


        //3.创建Thread类的子类的对象
     MyThread t1 = new MyThread();
        //4.通过此对象调用start()作用有两个:1.启动线程  2.调用当前线程的run()方法
        //只能调用一次  start ,想要再用  就再去new一个对象
         //  myThread.run();
         t1.setName("线程-1");
            t1.setPriority(Thread.MAX_PRIORITY);
        t1.start();
        Thread.currentThread().setName("主线程:");
        Thread.currentThread().setPriority(Thread.MIN_PRIORITY);

//        //如下操作仍然是在main线程中执行的
        for (int i = 0 ; i < 100 ; i++){
            if (i % 2 == 0 ){
                System.out.println(Thread.currentThread().getName() + ":"+Thread.currentThread().getPriority() +":"+i);
            }


            if (i == 20 ){
                try {
                    t1.join();//
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }


//        //创建thread类的匿名子类的方式
//        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();
    }
}

第二种方式:开发中常用的是实现Runnable接口

package com.sinosoft;

import sun.security.timestamp.TSRequest;

/**
 * @author lj
 * @Create 2020-11-28-16:38
 * @description  创建多线程的第二种方式:实现Runnable接口
 *  1.创建一个实现Runnable接口的类
 *  2.实现类去实现Runnable中的抽象方法:run()
 *  3.创建实现类的对象
 *  4.将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
 *  5.通过Thread类的对象调用start()
 *
 */

class MThread implements Runnable {


    @Override
    public void run() {

        for (int i = 0 ; i < 100 ; i++){
            if (i % 2 == 0){
                System.out.println(i);

            }        }

    }
}public class ThreadTest1 {

    public static void main(String[] args) {
        MThread  mThread = new MThread();
        Thread t1 = new Thread(mThread);
        Thread t2 = new Thread(mThread);
        t1.start();
        t2.start();
    }
}