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

多线程——线程相关概念
<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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
黑马程序员线程练习题主要包括两个问题。第一个问题是如何控制四个线程在打印log之前能够同时开始等待1秒钟。一种解决思路是在线程的run方法中调用parseLog方法,并使用Thread.sleep方法让线程等待1秒钟。另一种解决思路是使用线程池,将线程数量固定为4个,并将每个调用parseLog方法的语句封装为一个Runnable对象,然后提交到线程池中。这样可以实现一秒钟打印4行日志,4秒钟打印16条日志的需求。 第二个问题是如何修改代码,使得几个线程调用TestDo.doSome(key, value)方法时,如果传递进去的key相等(equals比较为true),则这几个线程应互斥排队输出结果。一种解决方法是使用synchronized关键字来实现线程的互斥排队输出。通过给TestDo.doSome方法添加synchronized关键字,可以确保同一时间只有一个线程能够执行该方法,从而实现线程的互斥输出。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [黑马程序员——多线程10:多线程相关练习](https://blog.csdn.net/axr1985lazy/article/details/48186039)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值