java学习笔记 --- 多线程(多线程的创建方式)

1、创建多线程方式1——继承Thread类。
   步骤:
       A:自定义类MyThread继承Thread类。
       B:MyThread类里面重写run()?
          为什么是run()方法呢?
       C:创建对象
       D:启动线程

/* 方式1:继承Thread类。
 * 步骤
 *         A:自定义类MyThread继承Thread类。
 *         B:MyThread类里面重写run()?
 *             为什么是run()方法呢?
 *         C:创建对象
 *         D:启动线程
 */
 public class MyThread extends Thread {//继承Thread类

/* 该类要重写run()方法,为什么呢?
 * 不是类中的所有代码都需要被线程执行的。
 * 而这个时候,为了区分哪些代码能够被线程执行,java提供了Thread类中的run()用来 包含那些被线程执行的代码。
 */

    @Override
    public void run() {
        // 自己写代码
        // System.out.println("好好学习,天天向上");
        // 一般来说,被线程执行的代码肯定是比较耗时的。所以我们用循环改进
        for (int x = 0; x < 200; x++) {
            System.out.println(x);
        }
    }

}
public class MyThreadDemo {
    public static void main(String[] args) {
        // 创建线程对象
        // MyThread my = new MyThread();
        // // 启动线程
        // my.run();
        // my.run();
        // 调用run()方法为什么是单线程的呢?
        // 因为run()方法直接调用其实就相当于普通的方法调用,所以你看到的是单线程的效果
        // 要想看到多线程的效果,就必须说说另一个方法:start()
        // 面试题:run()和start()的区别?
        // run():仅仅是封装被线程执行的代码,直接调用是普通方法
        // start():首先启动了线程,然后再由jvm去调用该线程的run()方法。
        // MyThread my = new MyThread();
        // my.start();
        // // IllegalThreadStateException:非法的线程状态异常
        // // 为什么呢?因为这个相当于是my线程被调用了两次。而不是两个线程启动。
        // my.start();

        // 创建两个线程对象
        MyThread my1 = new MyThread();
        MyThread my2 = new MyThread();

        my1.start();
        my2.start();
    }
}

 

2、线程对象调用 run方法和调用start方法区别?

线程对象调用run方法不开启线程。仅是对象调用方法。线程对象调用start开启线程,并让jvm调用run方法在开启的线程中执行。

3、为什么要重写run()方法?(和代码中注释的一个意思)

自定义线程需要执行的任务都定义在run方法中。Thread类中的run方法内部的任务并不是我们所需要,只有重写这个run方法,既然Thread类已经定义了线程任务的位置,只要在位置中定义任务代码即可。所以进行了重写run方法动作。

4、获取线程名称

public class MyThread extends Thread {//继承Thread内
    
         
    public MyThread() {
    }
    
    public MyThread(String name){
        super(name);
    }
        //重写run()方法
    @Override
    public void run() {
        for (int x = 0; x < 100; x++) {
            System.out.println(getName() + ":" + x);
        }
    }
}
/*
 * 如何获取线程对象的名称呢?
 * public final String getName():获取线程的名称。
 * 如何设置线程对象的名称呢?
 * public final void setName(String name):设置线程的名称
 * 
 * 针对不是Thread类的子类中如何获取线程对象名称呢?
 * public static Thread currentThread():返回当前正在执行的线程对象
 * Thread.currentThread().getName()
 */
public class MyThreadDemo {
    public static void main(String[] args) {
        // 创建线程对象
        //无参构造+setXxx()
        // MyThread my1 = new MyThread();
        // MyThread my2 = new MyThread();
        // //调用方法设置名称
        // my1.setName("线程1");
        // my2.setName("线程2");
        // my1.start();
        // my2.start();
        
        //带参构造方法给线程起名字
        // MyThread my1 = new MyThread("线程1");
        // MyThread my2 = new MyThread("线程2");
        // my1.start();
        // my2.start();
        
        //我要获取main方法所在的线程对象的名称,该怎么办呢?
        //遇到这种情况,Thread类提供了一个很好玩的方法:
        //public static Thread currentThread():返回当前正在执行的线程对象
        System.out.println(Thread.currentThread().getName());
    }
}

5、创建多线程的方法2——实现Runnable接口

  步骤:
       A:自定义类MyRunnable实现Runnable接口
       B:重写接口中的run()方法
       C:创建MyRunnable类的对象
       D:创建Thread类的对象,并把C步骤的对象作为构造参数传递

/*
 * 方式2:实现Runnable接口
 * 步骤:
 *         A:自定义类MyRunnable实现Runnable接口
 *         B:重写run()方法
 *         C:创建MyRunnable类的对象
 *         D:创建Thread类的对象,并把C步骤的对象作为构造参数传递
 */

public class MyRunnable implements Runnable {//步骤一:自定义类实现Runnable接口

    @Override
    public void run() {//重写run()方法
        for (int x = 0; x < 100; x++) {
            // 由于实现接口的方式就不能直接使用Thread类的方法了,但是可以间接的使用
            System.out.println(Thread.currentThread().getName() + ":" + x);
        }
    }

public class MyRunnableDemo {
    public static void main(String[] args) {
        // 创建MyRunnable类的对象
        MyRunnable my = new MyRunnable();

        // 创建Thread类的对象,并把C步骤的对象作为构造参数传递
        // Thread(Runnable target)
        // Thread t1 = new Thread(my);
        // Thread t2 = new Thread(my);
        // t1.setName("线程1");
        // t2.setName("线程2");

        // Thread(Runnable target, String name)
        Thread t1 = new Thread(my, "线程1");
        Thread t2 = new Thread(my, "线程2");

        t1.start();
        t2.start();
    }
}

6、实现Runnable的原理

 

  为什么需要定一个类去实现Runnable接口呢?继承Thread类和实现Runnable接口有啥区别呢?

 

     实现Runnable接口,避免了继承Thread类的单继承局限性。覆盖Runnable接口中的run方法,将线程任务代码定义到run方法中。创建Thread类的对象,只有创建Thread类的对象才可以创建线程。线程任务已被封装到Runnable接口的run方法中,而这个run方法所属于Runnable接口的子类对象,所以将这个子类对象作为参数传递给Thread的构造函数,这样,线程对象创建时就可以明确要运行的线程的任务。

7、实现Runnable的好处

 

  第二种方式实现Runnable接口避免了单继承的局限性,所以较为常用。实现Runnable接口的方式,更加的符合面向对象,线程分为两部分,一部分线程对象,一部分线程任务。继承Thread类,线程对象和线程任务耦合在一起。一旦创建Thread类的子类对象,既是线程对象,有又有线程任务。实现runnable接口,将线程任务单独分离出来封装成对象,类型就是Runnable接口类型。Runnable接口对线程对象和线程任务进行解耦。

 

posted @ 2017-03-26 13:34  皮皮虾我们上  阅读(275)  评论(0编辑  收藏  举报