Java多线程一(线程的三种创建方式)详细 简单 易懂

目录

1.什么是程序、进程与线程

 2.创建并启动线程

2.1继承Thread类方式

2.2实现Runnable接口方式

3运行结果

4.二者方式的区别

5.二者哪种方式较好

3. Thread类的常用结构

3.1 构造器

3.2 常用方法系列1

3.3 常用方法系列2

3.4 常用方法系列3

4.例题

4.1获取main线程和其他线程的名称和优先级。

4.2声明一个匿名内部类继承Thread类,重写run方法,实现打印[1,100]之间的偶数,要求每隔1秒打印1个偶数。

4.3线程停止与相互调度

 5.守护线程

5.1守护线程特点

5.2结论 


1.什么是程序、进程与线程

  1. 程序(program):为完成特定任务,用某种语言编写的一组指令的集合。即指一段静态的代码,静态对象。
  2. 进程(process):程序的一次执行过程,或是正在内存中运行的应用程序。如:运行中的QQ,运行中的网易音乐播放器。

  3. 线程(thread):进程可进一步细化为线程,是程序内部的一条执行路径。一个进程中至少有一个线程。

 2.创建并启动线程

2.1继承Thread类方式

public class MyThread extends Thread{
        public MyThread(String name){
            super(name);//设置线程名
        }
    /*
    * 重写run方法
    * 创建线程
    * */
    @Override
    public void run() {
            System.out.println(getName()+"正在执行!");
    }
}

运行线程

public class TestMyThread {
    public static void main(String[] args) {
        MyThread mt1 = new MyThread("子线程1");
        mt1.start();//start运行线程

        MyThread mt2 = new MyThread("子线程2");
        mt2.start();

        MyThread mt3 = new MyThread("子线程3");
        mt3.start();
    }
}

2.2实现Runnable接口方式

public class MyRunnable implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "正在运行!");
    }
}

运行线程

public class TestMyRunnable {
    public static void main(String[] args) {
        MyRunnable mr = new MyRunnable();
        Thread t1 = new Thread(mr,"子线程1");
        t1.start();
        Thread t2 = new Thread(mr,"子线程2");
        t2.start();
        Thread t3 = new Thread(mr,"子线程3");
        t3.start();
    }
}

3运行结果

 4.二者方式的区别

  • 当一个类扩展 Thread 类时,您不能扩展任何其他类,但通过实现 Runnable 接口,也可以从另一个类扩展,例如: class MyClass extends OtherClass implements Runnable.
  • 继承Thread:线程代码存放Thread子类run方法中。

  • 实现Runnable:线程代码存在接口的子类的run方法。

  • 实现Runnable不返回结果,也不能抛出已检查的异常。

5.二者哪种方式较好

实现Runnable接口比继承Thread类所具有的优势

  • 避免了单继承的局限性
  • 多个线程可以共享同一个接口实现类的对象,非常适合多个相同线程来处理同一份资源。
  • 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。

Runnable 接口非常适合于需要在多个线程之间共享任务逻辑的场合,以及那些简单且可重复使用的任务。 

6.第三种方式:Callable接口方式(JDK5.0新增)

点击查看(Callable详解)icon-default.png?t=N7T8https://blog.csdn.net/m0_61160520/article/details/131636644?spm=1001.2014.3001.5501

3. Thread类的常用结构

3.1 构造器

public Thread()分配一个新的线程对象。
public Thread(String name)分配一个指定名字的新的线程对象。
public Thread(Runnable target)指定创建线程的目标对象,它实现了Runnable接口中的run方法
public Thread(Runnable target,String name)分配一个带有指定目标新的线程对象并指定名字。

3.2 常用方法系列1

public void run() 此线程要执行的任务在此处定义代码。
public void start() 导致此线程开始执行; Java虚拟机调用此线程的run方法。
public String getName()获取当前线程名称。
public void setName(String name)设置该线程名称。
public static Thread currentThread() 返回对当前正在执行的线程对象的引用。在Thread子类中就是this,通常用于主线程和Runnable实现类
public static void sleep(long millis) 使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。
public static void yield()yield只是让当前线程暂停一下,让系统的线程调度器重新调度一次,希望优先级与当前线程相同或更高的其他线程能够获得执行机会,但是这个不能保证,完全有可能的情况是,当某个线程调用了yield方法暂停之后,线程调度器又将其调度出来重新执行。

3.3 常用方法系列2

public final boolean isAlive()测试线程是否处于活动状态。如果线程已经启动且尚未终止,则为活动状态。 
void join()等待该线程终止。 
void join(long millis)等待该线程终止的时间最长为 millis 毫秒。如果millis时间到,将不再等待。 
void join(long millis, int nanos)等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒。 

3.4 常用方法系列3

每个线程都有一定的优先级,同优先级线程组成先进先出队列(先到先服务),使用分时调度策略。优先级高的线程采用抢占式策略,获得较多的执行机会。每个线程默认的优先级都与创建它的父线程具有相同的优先级。

  • Thread类的三个优先级常量

  • public final int getPriority()返回线程优先级
    public final void setPriority(int newPriority)改变线程的优先级,范围在[1,10]之间
MAX_PRIORITY(10)最高优先级
MIN _PRIORITY (1)最低优先级
NORM_PRIORITY (5)普通优先级,默认情况下main线程具有普通优先级。

 

4.例题

4.1获取main线程和其他线程的名称和优先级。

声明一个匿名内部类继承Thread类,重写run方法,在run方法中获取线程名称和优先级。设置该线程优先级为最高优先级并启动该线程。

/*
* 获取main线程对象和其他线程的名称和优先级。
* 声明一个匿名内部类继承Thread类,重写run方法,在run方法中获取线程名称和优先级。
* 设置该线程优先级为最高优先级并启动该线程。
* 再次获取优先级
* */
public class Eg1 extends Thread{
    public static void main(String[] args) {
        Thread t1 = new Thread("线程1"){
            /*创建线程*/
            @Override
            public void run() {
                super.run();
                //输出默认优先级
                System.out.println(getName()+"的优先级为:"+getPriority());
            }
        };
        t1.setPriority(Thread.MIN_PRIORITY);//设置为最高优先级
        t1.start();//再运行
        System.out.println(t1.getName()+"的优先级为:"+t1.getPriority());
        System.out.println(Thread.currentThread().getName()+"的优先级为:"+Thread.
currentThread().getPriority());//main的优先级
    }
}

输出:

线程1的优先级为:1

main的优先级为:5

线程1的优先级为:1

 4.2声明一个匿名内部类继承Thread类,重写run方法,实现打印[1,100]之间的偶数,要求每隔1秒打印1个偶数。

public class Eg2 {
    public static void main(String[] args) {
        Thread te = new Thread(() -> {
            for (int i = 2; i <= 100; i += 2) {
                System.out.println("偶数:" + i);
                try {
                    Thread.sleep(1000);//使当前正在执行的线程暂停 1 millis(暂时停止执行)。
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        te.start();
    }
}

4.3线程停止与相互调度

  • 声明一个匿名内部类继承Thread类,重写run方法,实现打印[1,100]之间的偶数,要求每隔1秒打印1个偶数。
  • 声明一个匿名内部类继承Thread类,重写run方法,实现打印[1,100]之间的奇数,当打印到5时,让奇数线程暂停一下,再继续。当打印到5时,让奇数线程停下来,让偶数线程执行完再打印。
public class Eg3 {
    public static void main(String[] args) {
        Thread te = new Thread(() -> {
            for (int i = 2; i <= 20; i += 2) {
                System.out.println("偶数线程:" + i);
                try {
                    Thread.sleep(1000);//可以让程序放慢运行,然后让甲方加钱再优化(滑稽)
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        te.setPriority(Thread.MAX_PRIORITY);
        te.start();

        Thread to = new Thread(() -> {
            for (int i = 1; i <= 20; i += 2) {
                System.out.println("奇数线程:" + i);
                if (i == 5) {
                        Thread.yield();
/*yield让当前线程暂停一下,让系统的线程调度器重新调度一次,
*希望优先级与当前线程相同或更高的其他线程能够获得执行机会,
*但是这个不能保证,完全有可能的情况是,当某个线程调用了yield方法暂停之后,
*线程调度器又将其调度出来重新执行。*/
                    try {
                        te.join();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        to.start();
    }
}

输出: 

偶数线程:2

奇数线程:1

奇数线程:3

奇数线程:5

偶数线程:4

偶数线程:6

偶数线程:8

偶数线程:10

偶数线程:12

偶数线程:14

偶数线程:16

偶数线程:18

偶数线程:20

奇数线程:7

奇数线程:9

奇数线程:11

奇数线程:13

奇数线程:15

奇数线程:17

奇数线程:19

 5.守护线程

5.1守护线程特点

有一种线程,它是在后台运行的,它的任务是为其他线程提供服务的,这种线程被称为“守护线程”。JVM的垃圾回收线程就是典型的守护线程

守护线程有个特点,就是如果所有非守护线程都死亡,那么守护线程自动死亡。

public class Daemon extends Thread{
    public static void main(String[] args) {
        System.out.println("main开始进行");
        Thread t1 = new Thread("守护线程"){
            //创建线程
            @Override
            public void run() {
                super.run();
                for (int i = 1; i <= 10;i++) {
                    try {
                        Thread.sleep(1000);
                        System.out.println(Thread.currentThread().getName()+"正在运行第:"+i+"次");
                    } catch (InterruptedException e) {
                        System.out.println("休眠异常!");
                    }
                }
            }
        };
        Thread t2 = new Thread("普通线程"){
            //创建线程
            @Override
            public void run() {
                super.run();
                for (int i = 1; i <= 5;i++) {
                    try {
                        Thread.sleep(1000);
                        System.out.println(Thread.currentThread().getName()+"正在运行第:"+i+"次");
                    } catch (InterruptedException e) {
                        System.out.println("休眠异常!");
                    }
                }
            }
        };
        t1.setDaemon(true);
        t2.setDaemon(false);
        t1.start();
        t2.start();
        System.out.println("main结束进行");
    }
}

运行结果: 

5.2小结论 

  1. 主线程,main执行结束后,普通线程可以继续执行直至执行完毕;
  2. 用户线程执行完毕后,守护线程立刻结束;
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值