黑马程序员——多线程(上)

来源:互联网 发布:常见网络协议 编辑:程序博客网 时间:2024/05/16 00:31

多线程——线程相关概念
<span style="white-space:pre">基本概念线程:是依赖于进程的执行绪(执行路径/控制单元),是程序使用CPU的基本单位。进程:当前正在执行的程序,代表一个应用程序在内存中的执行区域。多进程:同一时间段内执行多个任务。同一时刻只能执行一个任务。如Windows为代表的操作系统。多进程并不提高某个程序的执行速度,仅仅是提高了CPU的使用率。真正的多进程执行是指多核同时计算。单线程:一个进程中,只有一个线程执行。多线程:同一个进程中,多个线程执行。这多个线程共享该进程资源(堆内存与方法区),栈内存独立,即每一个线程占用一个栈。</span>
<span style="white-space:pre"></span>线程两种调度模型:<span style="white-space:pre"></span>分时调度模型   所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间片。<span style="white-space:pre"></span>抢占式调度模型   优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个。(线程随机性)<span style="white-space:pre"></span>Java使用的为抢占调度模型。<span style="white-space:pre"></span>线程并行与线程并发<span style="white-space:pre"></span>线程并行:正常的多线程执行就是线程并行。即逻辑上同一时间同时运行。<span style="white-space:pre"></span>线程并发(异常):由于线程抢占而不应出现的某一时刻的线程及相关数据状态。如并发修改异常的产生。<span style="white-space:pre"></span>JVM的启动支持多线程:<span style="white-space:pre"></span>JVM启动至少启动了垃圾回收线程和主线程,所以是多线程的。<span style="white-space:pre"></span>Java命令会启动java虚拟机,启动JVM,等于启动了一个应用程序,也就是启动了一个进程。该进程会自动启动一个 “主线程”,然后主线程去调用<span style="white-space:pre"></span>某个类的 main 方法。所以 main方法运行在主线程中。
<span style="white-space:pre">线程Thread类常用方法</span>
<span style="white-space:pre">public Thread()</span><pre name="code" class="java" style="font-size: 13.3333339691162px;"><span style="white-space:pre"></span>空参构造<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px;"></span>

<span style="white-space:pre">public Thread(Runnable target)</span>使用多线程的对象
<span style="white-space:pre">public Thread(String name)分配新的 <code>Thread</code> 对象</span>并命名
<span style="white-space:pre">public Thread(Runnable target, String name)</span>
</pre><pre name="code" class="java">
</pre><pre name="code" class="java"><span style="white-space:pre"></span><span style="font-size: 13.3333339691162px; font-family: Arial, Helvetica, sans-serif;">使用多线程的对象并命名</span>
2多线程的两种创建方式及其特点
多线程实现方式方式一:继承Thread类自定义线程类继承Thread类。重写run方法。run方法内为该线程执行代码。将其理解为其他线程的main方法,即该线程的执行入口。使用:创建线程对象开启线程,即调用start方法,该方法会自动调用这个线程的run方法。方式二:实现Runnable接口自定义Runnable 的子类(非线程类)。重写run方法。run方法内为该类对象所在线程的执行代码。同样可将其理解为其他线程的main方法,即该线程的执行入口。使用:创建Runnable的子类对象。使用Runnable的子类对象创建线程对象。开启线程,即调用start方法,该方法会自动调用这个线程的run方法。
方式一与方式二的区别方式一:当类去描述事物,事物中有属性和行为。如果行为中有部分代码需要被多线程所执行,同时还在操作属性。就需要该类继承Thread类,产生该类的对象作为线程对象。可是这样做会导致每一个对象中都存储一份属性数据。无法在多个线程中共享该数据。加上静态,虽然实现了共享但是生命周期过长。方式一:如果一个类明确了自己的父类,那么它就不可以再继承Thread。因为java不允许类的多继承。方式二:将线程与运行的业务逻辑分离,可以让多个线程共享业务逻辑中的数据。方式二:可以让业务类不再继承Thread而专注于业务继承其他类,避免了单继承的局限性。
<span style="white-space:pre"></span>

线程优先级

线程优先级代表了抢占CPU的能力。优先级越高,抢到CPU执行的可能性越大。(一般环境下效果不明显,优先级并非绝对的执行顺序。)优先级相关方法:
public final void setPriority(int newPriority)
设定优先级取值:1-10
public final int getPriority()
获取
优先级

线程休眠

             指定线程休眠一定时间,进入等待状态。在该段时间结束后,线程重新可执行。线程休眠相关方法:
public static void sleep(long millis) throws InterruptedException

加入线程

等待某加入的线程终止后再执行。加入线程相关方法:
public final void join() throws InterruptedException

线程礼让

暂停当前正在执行的线程对象,并执行其他线程。(效果不明显,如果想保证完成线程相互等待一次执行,需要使用到后边的等待唤醒机制 )线程礼让相关方法:
public static void yield()

守护线程

  将该线程标记为守护线程。被守护的线程执行完毕时,程序即停止运行。守护线程执行完毕不影响被守护线程。必须在线程开启前设置守护线程。守护线程设置相关方法:
public final void setDaemon(boolean on)

线程中断

stop方法已过时,通常使用interrupt方法。
中断线程相关方法:
public void interrupt()   被中断的线程会报被中断异常,这时需要使用try/catch语句解决相关问题,线程后代码仍然可以继续执行
public final void stop()  (已过时)  直接停止线程,线程后代码无法被执行

线程安全问题

在多个线程同时运行时发生的异常情况统称为线程安全问题。线程安全问题在理想状态下,不容易出现,但一旦出现对软件的影响是非常大的。
产生原因&前提:
线程随机访问性
有多个线程并行
多个线程有共享数据
多个线程操作了共享数据
处理方式:
使用java提供的同步机制,使某一线程的完整动作执行完毕,其他线程再进行操作

Java同步机制:为解决同步问题而提供的工具
原子性操作:
在执行操作时,我们把一个完整动作可以称为一个原子性操作,是一个不可切割的动作。即不可被线程打断的操作。
synchronized 关键字:
同步代码块格式:
synchronized(锁对象){//该对象可以是任意对象
需要同步的代码;
}
锁:几个线程需要使用相同的锁对象进行同步操作,使用不同的锁是无法完成同步操作的。
Synchronized内需要同步的代码即为一个原子性操作。
同步方法:方法上声明,将所在对象作为默认锁,即this。
同步静态方法:将方法所在类作为默认所,即XX.class。
优点:解决了多线程安全问题
缺点:当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。对于一个简单操作,单线程速度更快。

0 0