Java,多线程,线程的两种创建方式

首先是多线程的一些相关概念:

相关概念:

程序(program):为完成特定任务,用某种语言编写的一组指令的集合。即指一段静态(指不在执行中)的代码。

进程(process):程序的一次执行过程,或是正在内存中运行的应用程序。

        ·每个进程都有一个独立的内存空间,系统运行一个程序即是一个进程从创建、运行到消亡的过程。(声明周期)

        ·程序是静态的,进程是动态的。

        ·进程作为操作系统调度和分配资源的最小单位(亦是系统运行程序的基本单位),系统在运行时会为每个进程分配不同的内存区域。

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

        ·一个进程同一时间若并行执行多个线程,就是多线程的。

        ·线程是作为CPU调度和执行的最小单位。

        ·一个进程中的多个线程共享相同的内存单元,它们从一个堆中分配对象,可以访问相同的变量和对象。这就使得线程间通信更简便、高效。但多个线程操作共享的系统资源就可能会带来安全的隐患。

        注:不同的进程之间是不共享内存的。进程之间的数据交换和通信的成本很高。

线程调度:

        ·分时调度:所有线程轮流使用CPU的使用权,并且平均分配每个线程占用CPU的时间。

        ·抢占式调度:让优先级高的线程以较大的概率优先使用CPU。如果线程的优先级相同,那么会随机选择一个(线程随机性),Java使用的为抢占式调度。

多线程程序的优点:

        提高应用程序的响应。对图形化界面更有意义,可增强用户体验。

        提高计算机系统CPU的利用率。

        改善程序结构。将既长又复杂的进程分为多个线程,独立运行,利于理解和修改。

并行与并发:

并行(parallel):指两个或多个事件在同一时刻发生。指在同一时刻,有多条指令在多个CPU上同时执行。

并发(concurrency):指两个或多个事件在同一个时间段内发生。即在同一段时间内,有多条指令在单个CPU上快速轮换、交替执行,使得在宏观上具有多个进程同时执行的效果。

Java,多线程,线程创建方式一:继承Thread类

 Java语言的JVM允许程序运行多个线程,使用java.lang.Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。

Thread类的特性:

    ①每个线程都是通过某个特定的Thread对象的run( )方法来完成操作的,因此把run( )方法称为线程执行体。

    ②通过该Thread对象的start( )方法来启动这个线程,而非直接调用run( )方法。

    ③想要实现多线程,必须在主线程中创建新的线程对象。

通过继承Thread类来创建并启动多线程的步骤如下:

①定义Thread的子类,并重写该类的run( )方法,该run( )方法的方法体就代表了线程需要完成的任务。

②创建Thread类的子类的实例,即创建了线程对象。

③调用线程对象的start( )方法来启动该线程。

start( )的作用:①启动线程②调用当前线程的run( )方法。

以下代码的实现为例:

两个线程分别遍历10000以内的偶数:

public class EvenNumberTest

{

    public static void main(String[] args)

    {

        //③创建当前Thread类的子类的对象
        PrintNumber t1 = new PrintNumber();
        //通过对象调用start()方法
        t1.start();

        //main方法所在的线程的执行的操作
        for (int i = 1; i <= 10000; i++)
        {
            if(i % 2 == 0)
            {
                System.out.println(i + "及你太美");
            }
        }
    }
}

//①创建一个继承于Thread的子类
class PrintNumber extends Thread
{
    //②重写Thread类的run方法,并将此线程的要执行的操作,声明在此方法体中

    @Override
    public void run()
    {
        for (int i = 1; i <= 10000; i++)
        {
            if(i % 2 == 0)
            {
                System.out.println(i);
            }
        }
    }
}

可以发现到两个进程的交替的运行的状况:

注意点一:

如果不调用start( )方法,直接调用run( )方法,便不会开启新的线程。

注意点二:

不能让已经start的线程,再次执行start( ),否则会报异常。正确做法应该是再创建一个新的对象,用新的对象调用start( )方法。

可以利用匿名内部类的方法写出   遍历100以内的奇数和偶数的俩个线程(创建两个匿名内部类(Thread类的子类的匿名)):

class EvenNumber extends Thread
{
    @Override
    public void run()
    {
        for (int i = 1; i <= 100; i++)
        {
            if(i % 2 == 0)
            {
                System.out.println(Thread.currentThread().getName() + ": " + i);
            }
        }
    }
}

class OddNumber extends Thread
{
    @Override
    public void run()
    {
        for (int i = 1; i <= 100; i++)
        {
            if(i % 2 == 1)
            {
                System.out.println(Thread.currentThread().getName() + ": " + i);
            }
        }
    }
}

public class PrintNumberTest

{
    public static void main(String[] args
    {
//        EvenNumber e = new EvenNumber();
//        OddNumber o = new OddNumber();
//        e.start();
//        o.start();

        //方式二
        new Thread(){
            public void run()
            {
                for (int i = 1; i <= 100; i++)
                {
                    if(i % 2 == 0)
                    {
                        System.out.println(Thread.currentThread().getName() + ": " + i);
                    }
                }
            }
        }.start();

        new Thread(){
            public void run()
            {
                for (int i = 1; i <= 100; i++)
                {
                    if(i % 2 == 1)
                    {
                        System.out.println(Thread.currentThread().getName() + ": " + i);
                    }
                }
            }
        }.start();
    }
}

Java,多线程,线程创建方式二:实现Runnable接口

步骤:

①创建一个实现Runnable接口的类

②实现接口中的run( )方法,将此线程要执行的操作,声明在此方法体中。

③创建当前实现类的对象

④将此对象作为参数传递到Thread类的构造器中,创建Thread类的实例。

⑤Thread类的实例调用start( )方法。

基本步骤的样例如下:

//①创建一个实现Runnable接口的类
class EvenNumberPrint implements Runnable
{
//②创建接口中的run()方法,将此线程要执行的操作,声明在此方法体中
    @Override
    public void run()
    {
        for (int i = 1; i <= 100; i++)
        {
            if(i % 2 == 0)
            {
                System.out.println(Thread.currentThread().getName() + ": " + i);
            }
        }
    }
}
public class EvenNumberTest
{
    public static void main(String[] args)
    {
        EvenNumberPrint e = new EvenNumberPrint();//创建Runnable类的实现类的对象。
        Thread thread = new Thread(e);//创建thread类的对象,调用参数为Runnable的实现类的构造器,将实现类的对象代入构造器中去。
        thread.start();//直接调用Thread的对象的start方法。
        for (int i = 1; i <= 100; i++)
        {
            if(i % 2 == 1)
            {
                System.out.println(Thread.currentThread().getName() + ": " + i);
            }
        }


        Thread tt = new Thread(e);//要再创建一条新的线程,执行同样的操作,不用再创建实现类的对象,只要再创建Thread的对象就可以,参数用的依然是同一个实现类的对象。
        tt.start();
    }
}
同样 可以利用匿名内部类的方法写出   遍历100以内的奇数和偶数的俩个线程:
public class PrintNumberTest
{
    public static void main(String[] args)
    {
//        EvenNumber ee = new EvenNumber();
//        OddNumber oo = new OddNumber();
//        Thread t1 = new Thread(ee);
//        Thread t2 = new Thread(oo);
//        t1.start();
//        t2.start();


        //匿名的Thread的子类,参数为匿名的Runnable的实现类的匿名对象。
        new Thread(new Runnable(){
            public void run()
            {
                for (int i = 1; i <= 100; i++)
                {
                    if(i % 2 == 0)
                    {
                        System.out.println(Thread.currentThread().getName() + ": " + i);
                    }
                }
            }
        }).start();
        new Thread(new Runnable(){
            public void run()
            {
                for (int i = 1; i <= 100; i++)
                {
                    if(i % 2 == 1)
                    {
                        System.out.println(Thread.currentThread().getName() + ": " + i);
                    }
                }
            }
        }).start();
    }
}


class EvenNumber implements Runnable
{
    public void run()
    {
        for (int i = 1; i <= 100; i++)
        {
            if(i % 2 == 0)
            {
                System.out.println(Thread.currentThread().getName() + ": " + i);
            }
        }
    }
}


class OddNumber implements Runnable
{


    @Override
    public void run()
    {
        for (int i = 1; i <= 100; i++)
        {
            if(i % 2 == 1)
            {
                System.out.println(Thread.currentThread().getName() + ": " + i);
            }
        }
    }
}
线程创建的俩种方式的对比:
共同点:
①启动线程,使用的都是Thread类中定义的start( )方法。
②创建的线程对象,都是Thread类或Thread的子类的实例。
不同点:
方式一是类的继承,方式二是接口的实现。
建议使用Runnable接口的方式
实现Runnable接口的方式的好处:
①一个类可以实现多个接口,避免了类的单继承的局限性。
②创建多个线程对象的构造器的参数(Runnable的实现类)可以使用同一个实现类的对象,更适合处理有共享数据的问题。
③实现了代码和数据的分离。
联系:
Thread类实现了Runnable接口。体现了代理模式。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

二狗mao

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

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

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

打赏作者

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

抵扣说明:

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

余额充值