Java学习day-20:多线程

一、程序、进程 、线程

1.程序Program:

是一个静态的概念,一般对应于操作系统中的一个可执行文件。

2.进程:

执行中的程序叫做进程(Process),是一个动态的概念。现代的操作系统都可以同时启动多个进程。

(1)特点:

1) 进程是程序的一次动态执行过程, 占用特定的地址空间。

2)每个进程由3部分组成:cpu、data、code。每个进程都是独立的,保有自己的cpu时间,代码和数据,即便用同一份程序产生好几个进程,它们之间还是拥有自己的这3样东西,这样的缺点是:浪费内存,cpu的负担较重。

3)多任务(Multitasking)操作系统将CPU时间动态地划分给每个进程,操作系统同时执行多个进程,每个进程独立运行。以进程的观点来看,它会以为自己独占CPU的使用权。

4)进程的查看:Windows系统: Ctrl+Alt+Del,启动任务管理器即可查看所有进程。

3.线程:

一个进程可以产生多个线程。同多个进程可以共享操作系统的某些资源一样,同一进程的多个线程也可以共享此进程的某些资源。

(1)特点:

1) 一个进程内部的一个执行单元,它是程序中的一个单一的顺序控制流程。

2)一个进程可拥有多个并行的(concurrent)线程。

3)一个进程中的多个线程共享相同的内存单元/内存地址空间,可以访问相同的变量和对象,而且它们从同一堆中分配对象并进行通信、数据交换和同步操作。

4)由于线程间的通信是在同一地址空间上进行的,所以不需要额外的通信机制,这就使得通信更简便而且信息传递的速度也更快。

5)线程的启动、中断、消亡,消耗的资源非常少。

4.线程和进程的区别:

(1)每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销。

(2)线程可以看成是轻量级的进程,属于同一进程的线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换的开销小。

(3)最根本的区别:进程是资源分配的单位,线程是调度和执行的单位。

(4)线程是进程的一部分,所以线程有的时候被称为轻量级进程。

(5)多进程: 在操作系统中能同时运行多个任务(程序)。

(6)多线程: 在同一应用程序中有多个顺序流同时执行。

(7)系统在运行的时候会为每个进程分配不同的内存区域,但是不会为线程分配内存(线程所使用的资源是它所属的进程的资源),线程组只能共享资源。

二、线程的操作

1.实现多线程:

(1)继承Tread类实现多线程

缺点:Java 中的类是单继承的,一旦继承了 Thread 类,就不允许再去继承其它的类。

步骤:

1)在Java中负责实现线程功能的类是java.lang.Thread 类。

2)通过创建 Thread的实例来创建新的线程。

3)重写Tread类中的run()方法;

4)调用Thread类的start()方法来启动一个线程。

代码截图
结果

(2)通过Runnable接口实现:

优点:在实现Runnable接口的同时还可以继承其它的类。

步骤:

1)编写类实现 Runnable 接口;

2)实现 run()方法;

3)通过 Thread 类的 start()方法启动线程;

代码截图
结果

(3)静态代理模式:

Thread:代理角色;

MyRunnable:真是绝色;

代理角色与真实角色实现共同的接口Runnable接口。

结果

2.线程的状态:

  一个线程对象在它的生命周期内,需要经历5个状态。

(1)新生状态: 用new关键字建立一个线程对象后,该线程对象就处于新生状态。处于新生状态的线程有自己的内存空间,通过调用start方法进入就绪状态。

(2)就绪状态:处于就绪状态线程具备了运行条件,但还没分配到 CPU,处于线程就绪队列,等待系统为其分配 CPU。当系统选定一个等待执行的线程后,它就会从就绪状态进入执行状态,该动作称为“CPU 调度”。

造成进入就绪态的原因:

1) 新建线程:调用start()方法,进入就绪状态;

2) 阻塞线程:阻塞解除,进入就绪状态;

3)运行线程:调用yield()方法,直接进入就绪状态;

4)运行线程:JVM将CPU资源从本线程切换到其他线程;

(3)运行状态:在运行状态的线程执行自己的 run 方法中代码,直到等待某资源而阻塞或完成任何而死亡。如果在给定的时间片内没有执行结束,就会被系统给换下来回到等待执行状态。

(4)阻塞状态:处于运行状态的线程在某些情况下,如执行了 sleep(睡眠)方法,或等待 I/O 设备等资源,将让出 CPU 并暂时停止自己运行,进入阻塞状态。在阻塞状态的线程不能进入就绪队列。只有当引起阻塞的原因消除时,如睡眠时间已到,或等待的I/O 设备空闲下来,线程便转入就绪状态,重新到就绪队列中排队等待,被系统选中后从原来停止的位置开始继续执行。

(5)死亡状态:

死亡状态是线程生命周期中的最后一个阶段。线程死亡的原因有三个,一个是正常运行的线程完成了它的全部工作;另一个是线程被强制性地终止,如通过 stop 方法来终止一个线程(不推荐使用);三是线程抛出未捕获的异常。

当一个线程进入死亡状态以后,就不能再回到其它状态了。

3.终止线程的方法:

终止线程一般不使用JDK提供的Stop()、destroy()方法。而是提供一个Boolean类型的终止的变量,当这个变量为false,则终止线程的运作。

代码截图
结果

4.暂停线程的方法:

(1)sleep()方法:可以让正在运行的线程进入阻塞状态,直到休眠时间满了,进入就绪状态。

(2)yield()方法:可以让正在运行的线程直接进入就绪状态,让出CPU的使用权。

代码截图
结果

5.线程的联合:

(1)join()方法:调用该方法的线程强制执行,其它线程处于阻塞状态,该线程执行完毕后,其它线程再执行。

(2)线程A在运行期间,可以调用线程B的join()方法,让线程B和线程A联合。

代码截图
结果

6.获取线程基本信息:

常用方法:

代码截图
结果

7.线程的优先级:

(1)线程的优先级:

1)处于就绪状态的线程,会进入“就绪队列”等待JVM来挑选。

2)线程的优先级用数字表示,范围从1到10,一个线程的缺省优先级是5。

(2)设置与获取优先级的方法:

1)设置优先级:final void setPriority(int priority);

2)获取优先级:final int getPriority();

代码截图
结果

三、线程的同步

1.什么是线程同步?

(1)线程同步的提出:现实生活中,我们会遇到“同一个资源,多个人都想使用”的问题。 比如:教室里,只有一台电脑,多个人都想使用。

(2)线程同步的概念: 处理多线程问题时,多个线程访问同一个对象,并且某些线程还想修改这个对象。我们就需要用到“线程同步”。 线程同步其实就是一种等待机制,多个需要同时访问此对象的线程进入这个对象的等待池形成队列,等待前面的线程使用完毕后,下一个线程再使用。

2.线程同步的实现:

(1)通过synchronize方法:(public  synchronized  void accessVal(int newVal))

synchronized 方法控制对“对象的类成员变量”的访问:每个对象对应一把锁,每个 synchronized 方法都必须获得调用该方法的对象的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。

缺陷:将一个大的方法声明为synchronized 将会大大影响效率。

(2)同步代码块:

synchronize(obj){//obj称为同步监视器

//允许访问控制的代码 

1)synchronized 代码块可以让我们精确地控制到具体的“成员变量”,缩小同步的范围,提高效率。

代码截图
结果

3.死锁的解决方法:

(1)死锁产生的原因:

多线程操作时,互相等待对方的资源。

(2)解决方法:

不要让两个对象同时持有对象锁,采用互斥来解决。

代码截图
结果

四、生产者/消费者模式

1.生产者与消费者模式:

 多线程环境下,我们经常需要多个线程的并发和协作。需要一个重要的多线程并发协作模型“生产者/消费者模式”。

原理:

(1)什么是生产者?

 生产者指的是负责生产数据的模块(这里模块可能是:方法、对象、线程、进程)。

(2)什么是消费者?

消费者指的是负责处理数据的模块(这里模块可能是:方法、对象、线程、进程)。

(3)什么是缓冲区?

消费者不能直接使用生产者的数据,它们之间有个“缓冲区”。生产者将生产好的数据放入“缓冲区”,消费者从“缓冲区”拿要处理的数据。

(4)线程的并发协作:

有了缓冲区以后,生产者线程只需要往缓冲区里面放置数据,而不需要管消费者消费的情况;同样,消费者只需要从缓冲区拿数据处理即可,也不需要管生产者生产的情况。  生产者不需要和消费者直接打交道。

(5)解决出现重复生产,重复取走。生产者生产数据慢时,缓冲区仍有数据,不影响消费者消费;消费者处理数据慢时,生产者仍然可以继续往缓冲区里面放置数据 。


代码截图
代码截图
结果

你可能感兴趣的:(Java学习day-20:多线程)