2021/8/31 Java第七章 多线程

1.什么是进程?

        进程(Process)是程序的一次动态执行过程,它对应了从代码加载丶执行至执行完毕的一个完整过程,这个过程也是进程本身从产生丶发展至消亡的过程。操作系统同时管理一个计算机系统中的多个进程,让计算机系统中的多个进程轮流使用CPU资源,或者共享操作系统的其他资源。

    进程的特点是:

  • 进程是系统运行程序的基本单位。
  • 每一个进程都有自己独立的一块内存空间丶一组系统资源。
  • 每一个进程的内部数据和状态都是完全独立的。                

2.什么是线程?

        线程是进程中执行运算的最小单位,可完成一个独立的顺序控制流程。每个进程中,必须至少建立一个线程(这个线程称为主线程)来作为这个程序运行的入口点。如果在一个进程中同时运行了多个线程,用来完成不同的工作,则称之为"多线程"。在操作系统将进程分成多个线程后,实际上每个任务是一个线程,多个线程共享相同的地址空间并且共同分享同一个进程,这些线程可以在操作系统的管理下并发执行。从而大大提高了程序的运行效率。虽然线程的执行看似是多个线程同时执行,但实际上并非如此。由于单CPU的计算机中,CPU同时只能执行一条指令,因此,在仅有一个CPU的计算机上不可能同时执行多个任务。而操作系统为了能提高程序的运行效率,将CPU的执行时间分成多个时间片,分配给不同的线程,当一个时间片执行完毕后,该线程就可能让出CPU使用权限交付给下一个时间片的其他线程执行。当然有可能相邻的时间片分配给同一线程。之所以表面上看是多个线程同时执行,是因为不同线程之间切换的时间非常短,也许仅仅是几毫秒,对普通人来说是难以感知的,这样就看似多个线程在同时执行了。

3.多线程的好处

  1. 充分利用CPU的资源:执行单线程程序时,若程序发生阻塞,CPU可能会处于空闲状态,这将造成计算机资源浪费,而使用多线程可以在某个线程处理休眠或阻塞状态时运行其他线程,这样,大大提高了资源利用率。
  2. 简化编程模型:一个既长又复杂的进程可以考虑分为多个线程,成为几个独立的运行部分,如使用时丶分丶秒来描述当前时间,如果写成单线程程序可能需要多重循环判断,而如果使用多线程,时丶分丶秒各使用一个线程控制,每个线程仅需实现简单的流程,简化了程序逻辑,这样更有助于开发人员对程序的理解和维护。
  3. 带来良好的用户体验:由于多个线程可以交替执行,减少或避免了因程序阻塞或意外情况造成的响应过慢现象,降低了用户等待的几率。

4.在Java中实现多线程

                                                        Thread类及其常用方法

构造方法  说明
Thread() 分配新的Thread对象 
Thread(Runnable target) 分配新的Thread对象,target为run()方法被调用的对象 
Thread(Runnable target,String name) 分配新的Thread对象,target为run()方法被调用的对象,name为新线程的名称
 void run() 执行任务操作的方法
void start() 使该线程开始执行,Java虚拟机调用该线程的run()方法
void sleep(long millis) 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)
String getName()  返回线程的名称
int getPriority()  返回线程的优先级
int setPriority(int newPriority) 更改线程的优先级
static Therad currentThread() 返回当前正在执行的线程对象的引用
boolean isAlive() 测试线程是否处于活动状态
void join() 使当前线程暂停执行,等待调用该方法的线程结束后再继续执行本线程
void interrupt() 中断线程
void yield() 暂停当前正在执行的线程对象,并执行其他线程

4.1.继承Thread类创建线程

        ①.定义MyTherad类继承Therad类

        ②.重写run()方法,在run()方法中实现数据输出

        ③.创建线程对象,调用start()方法启动线程

4.2.实现Runnable接口创建线程

        ①.定义MyRunnable类实现Runnable接口,并实现Runnable接口的run()方法,在run()方法中实现输出数据。

        ②.创建MyRunnable类的对象myRunnable

        ③.创建一个Thread类的对象myThread,将myRunnable对象作为Thread类构造方法的参数传入。

        ④.调用myThread对象的start()方法启动线程。

总结:

        两种创建线程的方式有各自的特点和应用领域:直接继承Thread类的方式,编写简单,可以直接操作线程,适用于单继承的情况;当一个线程继承了另一个类时,就只能用实现Runnable接口的方式来创建线程,而且这种方式还可以实现多个线程之间资源的共享。

5.线程的状态

        ①.Thread t1=new Thread(rd);                         创建状态

        ②.t1.start();                                                       线程就绪状态

        ③.CPU资源分配给你了 你开始执行了               运行状态

        ④.调用了Thread.sleep(100);                            休眠(阻塞)状态

                可能使线程暂停执行的条件如下。

  • 由于线程优先级比较低,因此它不能获得CPU资源
  • 使用sleep()方法使线程休眠
  • 通过调用wait()方法,使线程等待
  • 通过调用yield()方法,线程显式出让CPU控制权
  • 线程由于等待一个文件,I/O事件被阻塞                

        ⑤.System.exit(0)程序结束                                死亡状态

6.线程的同步

        1.同步方法​

           使用synchronized修饰的方法控制对类成员变量的访问。每个类实例对应一把锁,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。这种机制确保了同一时刻对应一个实例,从而有效避免了类成员变量的访问冲突。

        语法:

               访问修饰符 synchronized 返回值类型 方法名 (参数列表){///省略方法体......}

        或者

               synchronized 访问修饰符 返回值类型 方法名 (参数列表){///省略方法体......} 

        2.同步代码块

                代码块即使用{}括起来的一段代码,使用synchronized关键字修饰的代码块,称为同步代码块。

        语法:

              synchronized(this){///省略方法体......}  

                                            本章总结

1.多线程允许程序员编写可最大程度利用CPU的高效程序

2.在Java程序启动时,一个线程立刻运行,该线程通常称为程序的主线程。主线程的重要性体现在以下两个方面。

  • 它是产生其他子线程的线程
  • 通常它必须最后完成执行,因为它执行各种关闭动作

3.可通过两种方式创建线程

  • 声明一个继承了Thread类的子类,在此子类中,实现Therad类的run()方法
  • 声明一个实现Runnable接口的类,然后实现run()方法

4.每一个线程创建和死亡之前,均会处于创建丶就绪丶运行丶阻塞丶死亡状态之一

5.在Java实现的多线程应用程序中,可以通过调用Thread类中的方法来实现对线程对象的操作

  • 调整线程的优先级:Java线程有优先级,在同等情况下,优先级高的线程会获得较多的运行机会。Java线程的优先级用1~10的整数表示。
  • 线程休眠:sleep(long millis)方法使线程转到阻塞状态
  • 线程的强制运行:join()方法可以强制某一线程运行
  • 线程礼让:yield()方法,暂停当前正在执行的线程对象,把执行机会让给相同或者更高优先级的线程

6.当多个线程对象操纵同一共享资源时,要使用 synchronized关键字来进行资源的同步处理,可以使用同步方法和同步代码块来实现线程同步

练习小作业:

        ​​​​​​​1.创建两个线程。每个线程均输出20次消息数字丶"你好",线程名。并观察多个线程交替执行的过程。

        要求:

                使用继承Therad类的方式创建线程。

                实现Therad类的run()方法,编写线程执行体。

                使用start()方法启动线程。​​​​​​​

        2.修改题目1,要求线程类使用实现Runnable接口的方式创建,并修改测试类。运行效果与题目一一样。

        3.使用多线程模拟多人徒步爬山的过程,每个线程代表一个人,爬山的速度不同,每爬完100米显示信息,爬到终点时给出相应提示。需要设置爬山人名丶爬山的总千米数丶每爬100米的耗时。运行结果。

                要求:

                        使用任意一种方式创建线程

                        使用Thread.sleep()方法设置线程休眠

        4.任意创建一个线程类,在测试类中创建子线程对象,显示主线程丶子线程默认优先级,将主线程设置为最高优先级,子线程设置为最低优先级并显示。运行结果。

        5.某医院设置有普通号和特需号,假定某科室一天需看普通号50个,特需号10个,每个特需号的看病时间约是普通号的两倍。开始时普通号和特需号并行叫号,叫到特需号的概率比普通号高,当普通号叫完第10号时,要求先看完全部特需号,再看普通号,请使用多线程模拟这一过程。运行结果。

        6.学校召开春季运动会,现使用多线程模拟1000米接力赛跑,比赛地点在学校操场,有多人参加,每人跑100米,每跑10米显示信息,跑够100米之后将接力棒传给下一个选手。要求在跑的选手只有一人,跑到终点时结束。要求使用同步方法和同步代码块两种方式实现线程同步。运行结果。

                要求:

                        实现多线程间数据的共享

                        使用同步方法或同步代码块实现线程安全

        7."桃跑跑" "张票票" "黄牛党"共同抢十张票,限制黄牛党只能抢一次票,请使用多线程模拟此过程。运行结果。

你可能感兴趣的:(java,windows)