java核心编程-线程与进程

多线程

我们之前,学习的程序在没有语句跳转的前提下,都是由上自下依次执行,那现在向要设计一个程序,边打游戏,边听歌,如何设计?

要解决上述问题,就需要使用多进程或者多线程来解决。

1.线程:

主线程:执行main方法的线程

单线程程序:java中只有一个线程执行从main方法开始,从上到下依次执行,jvm执行main方法,main方法就会进入到栈内存,jvm就会找到操作系统开辟一条main方法通向cpu的执行路径,cpu就可以通过这个路径来执行main方法,而这个路径有一个名字,叫main线程

2.并发与并行

并发:指两个或者多个事件在同一时间段内发生

并行:指两个或者多个事件在同一时刻发生(同时发生)

在操作系统中,安装了多个程序,并发指的是在一段事件内宏观上有多个程序同时运行。在单cpu系统中,每一时刻只能有一道程序执行,即微观上这些程序都是分时交替运行的,只不过给人的感觉是同时运行,那是因为分时交替运行的时间是非常短的。

而在多个cpu系统中,则这些可以并发执行的程序便可以分配到多个处理器上(cpu)实现多任务并行执行,即利用每个处理器来处理一个可以并发的执行程序,这样多个程序便可以同时执行。目前电脑市场上说的多核cpu便是多核处理器,核越多,并行处理的程序越多,就能大大的提高电脑的运行效率。

注意: 单核处理器的计算机肯定是不能并行的处理多个任务的,只能是多个任务在单个cpu上并发运行。同理,线程也是一样,从宏观的角度上理解线程是并行运行的,但是从微观角度上是串行运行的,即一个线程一个线程的去执行,当系统只有一个cpu时,线程会以某种顺序执行多个线程,我们把这种情况称之为线程调度。

3.进程与线程

进程:是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程,进程也是程序的一个执行过程,是系统运行程序的基本单位,系统运行一个程序即是一个进程从创建、运行到消亡的过程。

线程:线程是进程中一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程,一个进程中可以有多个线程的,这个应用程序也可以称之为多线程程序。

简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程。

4.线程调度:

分时调度:所有的线程轮流使用cpu,平均分配每个线程占用cpu的时间。

抢占式调度:优先让优先级高的线程使用cpu,如果线程的优先级相同,那么会随机选择一个(线程的随机性)。

java使用的是抢占式调度。

5.创建线程类

java 使用 java.lang.Thread 类代表线程,所有的线程对象都必须是Thread类或者其子类的实例,每个线程的作用是完成一定的任务,实际上就是执行一段程序流,即一段顺序执行的代码。java使用线程执行体来代表这段程序流,java中通过继承Thread类可以创建并启动多线程。

步骤:

1.定义Thread类的子类,重写该类的run()方法,该run方法的方法体就代表了线程需要完成的任务,因此把run方法称为该线程的线程执行体。

2. 创建Thread子类的实例,即创建了线程对象 2. 调用线程对象的start() 方法,来启动线程,执行run方法。

代码示例:

自定义线程对象
public class MyThread extends Thread{
    //定义指定线程名字的构造方法
    public MyThread(String name){
        super(name);
    }
    /*
       重写run方法
     */
    @Override
    public void run(){
        for(int i=0;i<10;i++){
            System.out.println(getName()+"正在执行"+i);
        }
    }
}
测试类:
public class Test {
    public static void main(String[] args) {
        //创建自定义线程对象 并给出名字
        MyThread mt = new MyThread("新的线程");
        //开启线程
        mt.start();
        //在main方法中执行一个for循环
        for(int i=0;i<10;i++){
            System.out.println("main线程正在执行"+i);
        }
    }
}

多线程原理

通过上述代码,我们发现在测试类中仅执行一次for循环,但是控制台中却出现了2个for循环的打印,多出来的就是另一个线程帮助我们完成的。

分析:

程序启动运行main的时候,java虚拟机启动一个进程,主线程在main()调用的时候被创建,随着调用mt对象的start方法,另一个线程也启动了,这样整个应用就在多线程下运行。

0

通过此张图我们可以很清晰的看到多线程的执行流程,那么为什么可以完成并发执行呢?

多线程执行时,到底在内存中是如何运行的?

多线程执行时,在栈内存中,其实每个执行线程都有一片自己所属的栈内存空间,进行方法的压栈和弹栈。

图示:

 

0

当执行线程的任务结束了,线程自动在栈内存中释放了,但是当所有的执行线程都结束了,那么进程就结束了。

Thread类 (实现线程的方式一)

java.lang.Thread类,api中定义了有关线程的一些方法,具体如下:

构造方法:

  1. public Thread() 分配一个新的线程对象
  2. public Thread(String name) 分配一个指定名字的新的线程对象
  3. public Thread(Runnable target) 分配一个带有指定目标的新的线程对象
  4. public Thread(Runnable target,String name) 分配一个带有指定目标的线程对象并指定其名字

常用方法:

  1. public String getName() 获取当前线程的名字
  2. public void start() 导致此线程开始执行,java虚拟机调用此线程的run方法
  3. public void run() 此线程要执行的任务在此处定义
  4. public static void sleep(long mills) 使当前在执行的线程以指定的毫秒数暂停(暂时停止执行)
  5. public static Thread currentThread() 返回当前正在执行的线程的对象引用

实现Runnable(实现线程方式二)

java.lang.Runnable 也是非常常见的一种实现线程的方式,我们只需要重写run方法即可。

归根结底,我们的线程对象必须是Thread类型,而我们第二种实现Runnable接口的方式去实现线程,也是要构建Thread类型的对象

如何实现?创建Runnable接口 实现类,把该实现类的对象作为Thread类型的构造方法中的参数Thread (Runnable target)

实现步骤:

1.定义Runnable接口的实现类,并重写run方法,该run方法的方法体才是真正的线程执行体

2.创建Runnable接口实现类的对象,并以此示例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象

3.调用线程对象的strat方法来启动线程。

代码示例:

自定义Runnable接口实现类:
public class MyRunnable implements Runnable{
    @Override
    public void run() {
        for(int i=0;i<10;i++){
            System.out.println(Thread.currentThread().getName()+"  "+i);
        }
    }
}
测试类:
public class Demo {
    public static void main(String[] args) {
        //创建自定义实现类对象 用来作为参数构建Thread线程对象
        MyRunnable mr = new MyRunnable();
        //真正的创建线程对象
        Thread t = new Thread(mr, "张三");
        //开启线程
        t.start();
        for(int i=0;i<10;i++){
            System.out.println("李四"+i);
        }
    }
}

通过实现runnable接口,使得该类具有了多线程类的特征,run方法是多线程程序的一个执行目标,所有的多线程代码都在run方法里面,Thread类实际上也是实现了Runnable接口的类。(把Thread类作为线程类的标杆)

在启动多线程的时候,需要先通过Thread类的构造方法Thread(Runnable target)创建Thread类型对象,然后调用Thread对象的start方法来运行多线程的代码。

实际上所有的多线程代码都是通过运行Thread的start方法来运行的,因此,不管是继承Thread类还是实现Runnable接口来实现多线程,最终还是通过Thread对象的构造方法来创建Thread类型独享,并用Thread对象来控制线程的,熟悉Thread类的常用方法是进行多线程程序编程的基础。

注意:

Runnable类型对象仅仅作为Thread对象的target,runnable实现类里面包含的run方法仅作为线程执行体,而实际线程对象依然是Thread实例,只是该Thread线程负责执行target里面的run方法。

Thread和Runnable区别:

如果一个类继承Thread,则不适合资源共享,但是如果实现了Runnable接口的话,则很容易实现资源共享。

总结: 实现Runnable接口比继承Thread类具有的优势

1.适合多个相同的程序代码的线程去共享同一个资源。

2.可以避免java中单继承的局限性

3.增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。

4.线程池只能放入实现runnable接口或callable接口的线程类,不能直接放入继承Thread的类。

思考:在java中,每次程序运行至少要运行几个线程?

至少要执行2个线程,一个是main线程,另一个是java垃圾回收机制

匿名内部类方式实现线程的创建

使用线程的匿名内部类方式创建,可以方便的实现每个先测过执行不同的线程任务操作。

使用匿名内部类的方式实现runnable接口,重写runnable接口中的run方法:

代码示例:

public class NoNameInnerClassThread {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i=0;i<10;i++){
                    System.out.println("李四"+i);
                }
            }
        }).start();
​
        for (int i=0;i<10;i++){
            System.out.println("张三"+i);
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值