java基础之多线程实现方式(适合小白)

3 篇文章 0 订阅
2 篇文章 0 订阅

  这是笔者的第一篇博客,不喜轻喷。。。

  在各位大佬的java之路上的第一个程序十有八九是一个在main方法中打印“Hello world”。这便是一个最为简单的单线程程序。

  关于进程和线程之间的关系,网上的专业解释并不少,这里不再赘述。下面给出win10系统下的任务管理器-详细信息界面。

这里的idea64就是一个进程。在cpu使用抢占式调度策略下,可以通过设置改进程的优先级使其优先获得CPU的资源。总所周知的是,java虚拟机同样采用的是抢占式调度模型,优先级更高的线程则会被优先调用。

说回之前的main方法。

在这个main方法中,依次创建了两个对象,并执行run方法。以下是Person类代码:

运行结果很简单,从上到下依次运行p1和p2的run方法。一旦p1运行的过程中抛出异常,则程序终止。p2.run()不会被执行。

这里多线程的优点便能很好地体现出来。多个线程运行期间互不干扰,相比于单线程运行效率会更高。

那么问题来了:如何让代码变得“多线程”?

java中给出了Thread类。以下是笔者的Thread01类。

public class ThreadDemo {
    public static void main(String[] args) {
        Thread01 td1 = new Thread01();
        td1.start();

        for (int i=1;i<=20;i++){
            System.out.println("main:" + i);
        }
    }
}

这时再去执行上述代码,会发现结果与之前并不一样(随机打印)。

通过控制台可以很清楚的看到,ThreadDemo类和Thread01类中的打印方法交替执行,并不像之前从上到下顺序执行。由于这两个线程的优先级一样,他们被调用的概率相等,所以再次运行可以看到与之前不尽相同的结果(抢夺cpu资源,谁抢到谁执行):

在上述demo中,先开辟一个栈,main方法首先压栈执行。当运行到new Thread01的时候,会新创建一个对象放入堆内存。

注意:如果将main方法中调用start方法更改成run方法,则改程序会变为由main方法执行的单线程程序。run方法进入栈。

如果调用start方法,则会开辟一个新的栈空间,run方法进入新开辟的栈空间并执行。如果再次调用start,则会再次开辟新空间执行run方法(用新的对象调用start,否则会抛异常java.lang.IllegalThreadStateException
    at java.lang.Thread.start(Thread.java:708))。

下面说说创建线程的第二种方法。

从jdk源码中可以看到,Thread存在一个带参数的构造方法,其参数为实现了Runnable接口的实现类的对象。

废话不多说,直接上代码:

然后在主方法中创建并调用:

得到运行结果:

那么这两种创建多线程的方法有什么区别,我们在使用的时候应该选择哪一种呢?

如果一个类继承Thread,则不适合资源共享;实现Runnable接口则更容易实现资源共享。

使用实现接口的方式可以很好地避免java中单继承的局限性。如果继承了Thread类则不能继承其他类,而实现接口的同时还能继承其他类或者实现其他接口。

同时使用接口可以大大增强程序的扩展性(解耦)。把设置线程任务和开启新线程进行了分离。传递不同的实现类,赋予线程不同的任务。

最后,线程池中只能放入实现Runnable或者Callable类线程,不能放入继承Thread的类

多一句,每一个java程序运行都至少创建了两个线程。一个是你的代码(main方法),一个是jvm。

以下给出匿名内部类创建多线程的方法:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值