乐趣区

关于多线程:多线程原理和常用方法以及Thread和Runnable的区别

多线程原理

随机性打印

CPU 有了两条执行的门路,CPU 就有了抉择,一会执行 main 办法 一会执行 run 办法。也能够说两个线程,一个 main 线程 一个 run 线程 一起申请 CPU 的执行权(执行工夫)谁抢到了就执行对应的代码

多线程内存图解

  1. main 办法的第一步创建对象,创建对象开拓堆内存存储在堆内存中(地址值赋值给变量名 0x11)
  2. mt.run()调用时 run 办法被压栈进来 其实是一个单线程的程序(main 线程,会先执行完 run 办法再执行主线程中的去其余办法)
  3. mt.start()调用时会开拓一个新的栈空间。执行 run 办法(run 办法就不是在 main 线程执行,而是在新的栈空间执行,如果再 start 会再开拓一个栈空间再多一个线程)

对 cpu 而言,cpu 就有了抉择的权力 能够执行 main 办法、也能够执行两个 run 办法。多线程益处:多线程执行时,在栈内存中,其实每一个执行线程都有一片本人所属的栈内存空间,多个线程互不影响 进行办法的压栈和弹栈。

Thread 类的罕用办法

获取线程名称 getName()

public static void main(String[] args) {
    // 创立 Thread 类的子类对象
    MyThread mt = new MyThread();
    // 调用 start 办法, 开启新线程, 执行 run 办法
    mt.start();

    new MyThread().start();
    new MyThread().start();

    // 链式编程
    System.out.println(Thread.currentThread().getName());
}

/**
    获取线程的名称:
        1. 应用 Thread 类中的办法 getName()
            String getName() 返回该线程的名称。2. 能够先获取到以后正在执行的线程, 应用线程中的办法 getName()获取线程的名称
            static Thread currentThread() 返回对以后正在执行的线程对象的援用。* @author zjq
 */
// 定义一个 Thread 类的子类
public class MyThread extends Thread{
    // 重写 Thread 类中的 run 办法, 设置线程工作
    @Override
    public void run() {
        // 获取线程名称
        //String name = getName();
        //System.out.println(name);

        // 链式编程
        System.out.println(Thread.currentThread().getName());
    }
}

输入如下:

main
Thread-2
Thread-0
Thread-1

设置线程名称 setName() 或者 new Thread(“线程名字”)

  1. 应用 Thread 类中的办法 setName(名字) void setName(String name) 扭转线程名称,使之与参数 name 雷同。
  2. 创立一个带参数的构造方法, 参数传递线程的名称; 调用父类的带参构造方法, 把线程名称传递给父类, 让父类 (Thread) 给子线程起一个名字
  3. Thread(String name) 调配新的 Thread 对象。复制代码

代码案例:

// 开启多线程
MyThread mt = new MyThread();
mt.setName("小强");
mt.start();

// 开启多线程
new MyThread("旺财").start();

使以后正在执行的线程以指定的毫秒数暂停 sleep(long millis)

代码案例:

public static void main(String[] args) {
        // 模仿秒表
        for (int i = 1; i <=60 ; i++) {System.out.println(i);

            // 应用 Thread 类的 sleep 办法让程序睡眠 1 秒钟
            try {Thread.sleep(1000);
            } catch (InterruptedException e) {e.printStackTrace();
            }
        }
    }

创立多线程程序的第二种形式 - 实现 Runnable 接口

实现 Runnable 接口实现多线程的步骤:

  1. 创立一个 Runnable 接口的实现类
  2. 在实现类中重写 Runnable 接口的 run 办法, 设置线程工作
  3. 创立一个 Runnable 接口的实现类对象
  4. 创立 Thread 类对象, 构造方法中传递 Runnable 接口的实现类对象
  5. 调用 Thread 类中的 start 办法, 开启新的线程执行 run 办法

代码案例如下:

/**
 * 1. 创立一个 Runnable 接口的实现类
 * @author zjq
 */
public class RunnableImpl implements Runnable{
    //2. 在实现类中重写 Runnable 接口的 run 办法, 设置线程工作
    @Override
    public void run() {for (int i = 0; i <20 ; i++) {System.out.println(Thread.currentThread().getName()+"-->"+i);
        }
    }
}

public static void main(String[] args) {
    //3. 创立一个 Runnable 接口的实现类对象
    RunnableImpl run = new RunnableImpl();
    //4. 创立 Thread 类对象, 构造方法中传递 Runnable 接口的实现类对象
    Thread t = new Thread(run);// 打印线程名称
    //5. 调用 Thread 类中的 start 办法, 开启新的线程执行 run 办法
    t.start();

    for (int i = 0; i <20 ; i++) {System.out.println(Thread.currentThread().getName()+"-->"+i);
    }
}

Thread 和 Runnable 的区别

实现 Runnable 接口创立多线程程序的益处:

1. 防止了单继承的局限性

一个类只能继承一个类(一个人只能有一个亲爹), 类继承了 Thread 类就不能继承其余的类。实现了 Runnable 接口, 还能够继承其余的类, 实现其余的接口。

2. 加强了程序的扩展性, 升高了程序的耦合性(解耦)

实现 Runnable 接口的形式, 把设置线程工作和开启新线程进行了拆散(解耦)。实现类中, 重写了 run 办法: 用来设置线程工作。创立 Thread 类对象, 调用 start 办法: 用来开启新线程。

应用匿名外部类开启线程

匿名外部相似开启线程能够简化代码的编码。代码案例如下:

/**
    匿名外部类形式实现线程的创立

    匿名: 没有名字
    外部类: 写在其余类外部的类

    匿名外部类作用: 简化代码
        把子类继承父类, 重写父类的办法, 创立子类对象合一步实现
        把实现类实现类接口, 重写接口中的办法, 创立实现类对象合成一步实现
    匿名外部类的最终产物: 子类 / 实现类对象, 而这个类没有名字

    格局:
        new 父类 / 接口(){反复父类 / 接口中的办法};
 * @author zjq

 */
public class Demo01InnerClassThread {public static void main(String[] args) {
        // 线程的父类是 Thread
        // new MyThread().start();
        new Thread(){
            // 重写 run 办法, 设置线程工作
            @Override
            public void run() {for (int i = 0; i <20 ; i++) {System.out.println(Thread.currentThread().getName()+"-->"+"詹");
                }
            }
        }.start();

        // 线程的接口 Runnable
        //Runnable r = new RunnableImpl();// 多态
        Runnable r = new Runnable(){
            // 重写 run 办法, 设置线程工作
            @Override
            public void run() {for (int i = 0; i <20 ; i++) {System.out.println(Thread.currentThread().getName()+"-->"+"线程");
                }
            }
        };
        new Thread(r).start();

        // 简化接口的形式
        new Thread(new Runnable(){
            // 重写 run 办法, 设置线程工作
            @Override
            public void run() {for (int i = 0; i <20 ; i++) {System.out.println(Thread.currentThread().getName()+"-->"+"zjq");
                }
            }
        }).start();}
}
退出移动版