三.多线程的创建方法

创建方法总结

  1. 继承Thread类创建线程
  2. 实现Runnable创建线程
  3. 使用匿名内部类的形式创建线程
  4. 使用lambda表达式创建线程
  5. 使用Callable和Future创建线程
  6. 使用线程池例如用Executor框架创建线程
  7. spring@Async异步注解创建线程

方法一: 继承Thread类

public class Demo01 {
    public static void main(String[] args) {  //main()是主线程
        MyThread myThread = new MyThread();//创建线程MyThread的线程对象

        //启动线程调用的是start()方法,而不是run()方法
        myThread.start();//开启线程
        while (true) {//通过死循环语句打印输出
            System.out.println("main()方法在运行");
        }
    }
}
class MyThread extends Thread {
    //线程执行的程序就是在run()方法中
    public void run() {
        while (true) {//通过死循环语句打印输出
            System.out.println("MyThread()类的run()方法在运行");
        }
    }
}

运行结果

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5LiA6LW35Yqg5rK55a2mSmF2YQ==,size_14,color_FFFFFF,t_70,g_se,x_16

 利用两个while来模拟多线程环境,从运行结果,可以看到两个循环中的语句都有输出,说明该文件实现了多线程。

 通过继承Thread类可以实现多线程,但是这种方式有一定的局限性。因为java只支持单继承,一个类一旦继承了某个父类就无法继承Thread类。为了克服这种弊端,Thread类提供了另外一个构造方法Thread(Runnable target),其中runnable是一个接口,它只有一个run()方法。

 方法二:实现Runnable

public class Demo02 {
    public static void main(String[] args) {
        MyThread02 myThread = new MyThread02();//建线程MyThread的实例对象
        Thread thread=new Thread(myThread);//创建线程对象
        thread.start();//开启线程,执行线程中的run()方法
        while (true) {//通过死循环语句打印输出
            System.out.println("main()方法在运行");
        }

    }

}
class MyThread02 implements Runnable {
    public void run() {//线程的代码段,当调用start()方法时,线程从此处开始执行
        while (true) {//通过死循环语句打印输出
            System.out.println("MyThread()类的run()方法在运行");
        }
    }
}

运行结果

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5LiA6LW35Yqg5rK55a2mSmF2YQ==,size_12,color_FFFFFF,t_70,g_se,x_16

MyThread02类中重写了Runnable接口中的run()方法。main()方法中通过Thread类的构造方法将MyThread02类的实例对象作为参数传入。从运行结果,可以看到两个循环中的语句都有输出,说明该文件实现了多线程。

 直接继承Thread类和实现Runnable接口都能实现多线程,那么这两种实现多线程的方式在实际应用中有什么区别?

假设售票厅有四个窗口可发售某日某次列车的100张车票,这时,100张车票可以看做共享资源,四个窗口可以创建四个线程。为了更直观显示窗口情况,可以通过Thread的currenthread()方法得到当前线程的实例对象,然后调用gwtName()方法获取现成的名称。

案例方法一:通过继承Thread类创建多线程

public class Demo03 {
    public static void main(String[] args) {
        new TicketWindowThread().start();//创建第一个线程对象TicketWindow并开启
        new TicketWindowThread().start();//创建第二个线程对象TicketWindow并开启
        new TicketWindowThread().start();//创建第三个线程对象TicketWindow并开启
        new TicketWindowThread().start();//创建第四个线程对象TicketWindow并开启
    }
}
class TicketWindowThread extends Thread{
    private int tickets=100;
    public void run(){
        while (true) {//通过死循环打印语句
            if (tickets > 0) {
                Thread th = Thread.currentThread();//获取当前线程
                String th_name = th.getName();//获取当前线程的名字
                System.out.println(th_name + "正在发售第" + tickets-- + "张票");
            }
        }
    }
}

运行结果

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5LiA6LW35Yqg5rK55a2mSmF2YQ==,size_9,color_FFFFFF,t_70,g_se,x_16

 结果分析

  • 从运行结果可以看出,每张票都被打印了四次。出现这样现象的原因是四个线程没有共享100张票,而是各自出售了100张票。
  • 在程序中创建了四个ThreadWindow对象,就等于创建了四个售票程序,每个程序中都有100张票,每个线程在独立的处理各自的资源。
  • 注意:每个线程都有自己的名字,主线程默认的名字是“main”,用户创建的第一个线程的名字默认为“Thread_0”,第二个默认为“Thread_1”,以此类推。
  • 如果希望指定现成的名称,可以通过调用setName(String name)方法为线程设置名字。
  • 由于现实中铁路系统的票资源是共享的,一次上面的运行结果是不合理的。
  • 为了保证资源共享,在线程中只能创建一个售票对象,然后开启多个线程去运行同一个售票对象的售票方法。简单来说,就是四个线程运行同一个售票程序,就需要创建现成的第二种实现方法。

案例方法二:通过实现Runnable接口创建多线程

public class Demo04 {
    public static void main(String[] args) {
        TicketWindowRunnable tw = new TicketWindowRunnable();//创建TicketWindow实例对象tw
        new Thread(tw, "窗口1").start();//创建线程对象并命名为“窗口1”,开启线程
        new Thread(tw, "窗口2").start();//创建线程对象并命名为“窗口2”,开启线程
        new Thread(tw, "窗口3").start();//创建线程对象并命名为“窗口3”,开启线程
        new Thread(tw, "窗口4").start();//创建线程对象并命名为“窗口4”,开启线程
    }
}
class TicketWindowRunnable implements Runnable{
    private int tickets=100;
    public void run(){
        while(true){
            if(tickets>0){
                Thread th = Thread.currentThread();//获取当前线程
                String th_name = th.getName();//获取当前线程的名字
                System.out.println(th_name + "正在发售第" + tickets-- + "张票");
            }
        }
    }
}

运行结果

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5LiA6LW35Yqg5rK55a2mSmF2YQ==,size_7,color_FFFFFF,t_70,g_se,x_16

 结果分析

上述代码创建了TicketWindowRunnable对象并实现了Runnable接口,然后再main方法中创建了四个线程,在每个线程上都去调用这个TicketWindowRunnable对象中的run()方法,这样就可以确保四个线程访问的是同一个tickets变量,共享100张车票。

实现Runnable接口相对于继承Thread类来说的优势

  1. 适合多个相同程序代码的线程去处理同一个资源的情况,把线程同程序代码,数据有效地分离,很好的体现了面向对象的设计思想。
  2. 可以避免由于Java的单继承带来的局限性,在开发中经常碰到这样的一种情况。及使用一个已经继承了某个类的子类来创建线程,由于一个类不能同时有两个父类,因此就不能使用继承Thread类的方式。

 提示:JDK8简化了多线程的创建方法,在创建线程时指定线程要调用的方法。

格式如下:

Thread t=new Thread(() ->{
    //main方法代码
});

public class Demo05 {
    public static void main(String[] args) {
        Thread t=new Thread(() ->{
            while(true){
                System.out.println("start new thread!");
            }
        });
        t.start();//启动新线程
    }
}
class MyThread05 extends Thread{
    public void run() {
        while (true) {
            System.out.println("MyThread()类的run()方法在运行");
        }
    }
}

               

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

享受当下.26

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值