初步了解JAVA线程

多线程

并发与并行

  • 并发:指两个或多个事件在同一个时间段内发生。(交替发生)
  • 并行:指两个或多个事件在同一时刻发生(同时发生)。

线程与进程

  • 进程:是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间;进程也是程序的一次执行过程,是系统运行程序的基本单位。
  • 线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。

线程调度

  • 分时调度:所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间。
  • 抢占式调度:优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性),Java使用的为抢占式调度。

创建线程类

  • .定义Thread类的子类(可以使用匿名内部类创建),并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务,因此把run()方法称为线程执行体。
  • 创建Thread子类的实例,即创建了线程对象。
  • 调用线程对象的start()方法来启动该线程。(多次启动一个线程是非法的,特别是当线程已经结束执行后,不能重新启动。)

创建线程方式二

  • 定义Runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。
  • 创建一个Runnable接口的实现类对象。(可以使用匿名内部类创建)
  • 创建Thread类对象,通过构造方法中传递Runnable接口的实现类对象。
  • 调用Thread类中的start()方法来启动该线程。(实际的线程对象依然是Thread实例,只是该Thread线程负责执行其Runnable的run()方法。)

实现Runnable接口比继承Thread类所具有的优势

  • 避免了单继承的局限性。(实现Runnable接口,还可以继续继承其他的类,实现其他接口)
  • 增强了程序的扩展性,降低了程序的耦合性。(Runnable接口方式,把设置线程任务和启动新县城进行了分离)

线程安全

多线程访问了共享的数据,且多个线程中对资源有写的操作,就会产生线程安全问题。(全局变量及静态变量)
同步代码块

synchronized(同步锁){
	需要同步操作的代码
}
  • 通过代码块中的锁对象可以使用任意对象。(对象监视器)
  • 必须保证多个线程使用的锁对象是同一个。(定义在run方法外)
  • 锁对象作用:把同步代码块锁住,只让一个线程在同步代码块执行。

同步方法

修饰符 synchronized 返回值类型 方法名 (参数列表){
	// 可能出现线程安全的代码(访问了共享数据的代码)
}
  • 同步锁,对于非static方法,同步锁就是this。对于static方法,我们使用当前方法所在类的字节码对象(类名.class)。

Lock锁

  • 在成员位置创建一个ReentrantLock对象。
  • 在可能出现安全问题的代码前调用Lock接口中的方法lock()获取锁。
  • 在可能出现安全问题的代码后调用Lock接口中的方法unlock()释放锁。(优化代码会写在finally中,无论是否报错都会释放锁)

线程状态

线程状态导致状态发生条件
NEW(新建)线程刚被创建,但是并未启动。还没调用start方法。
Runnable(可运行)线程可以在java虚拟机中运行的状态,可能正在运行自己代码,也可能没有,这取决于操作系统处理器。
Blocked(锁阻塞)当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状态;当该线程持有锁时,该线程将变成Runnable状态。
Waiting(无限等待)一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入Waiting状态。进入这个状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAll方法才能够唤醒。
TimedWaiting(计时等待)同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。这一状态将一直保持到超时期满或者接收到唤醒通知。带有超时参数的常用方法有Thread.sleep 、Object.wait。
Teminated(被终止)因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡。

等待唤醒机制

线程间通信
多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同。
如何保证线程间通信有效利用资源
多个线程在处理同一个资源,并且任务不同时,需要线程通信来帮助解决线程之间对同一个变量的使用或操作。 就
是多个线程在操作同一份数据时, 避免对同一共享变量的争夺。也就是我们需要通过一定的手段使各个线程能有效
的利用资源。而这种手段即—— 等待唤醒机制。
等待唤醒机制

  • 是多个线程间的一种协作机制。
  • wait/notify 就是线程间的一种协作机制。

等待唤醒中的方法

  • wait:线程不再活动(进入 wait set 中),不再参与调度。
  • notify:选取所通知对象的 wait set 中的一个线程释放,重新进入到调度队列(ready queue)中。
  • notifyAll:释放所通知对象的 wait set 上的全部线程。
  • 注意:哪怕只通知了一个等待的线程,被通知线程也不能立即恢复执行,因为它当初中断的地方是在同步块内,而此刻它已经不持有锁,所以她需要再次尝试去获取锁(很可能面临其它线程的竞争),成功后才能在当初调用 wait 方法之后的地方恢复执行。(如果能获取锁,线程就从 WAITING 状态变成 RUNNABLE 状态;否则,从 wait set 出来,又进入 entry set,线程就从 WAITING 状态又变成 BLOCKED 状态)

调用wait和notify方法注意细节

  • wait方法与notify方法是属于Object类的方法的。因为:锁对象可以是任意对象,而任意对象的所属类都是继承了Object类的。
  • wait方法与notify方法必须要由同一个锁对象调用。因为:对应的锁对象可以通过notify唤醒使用同一个锁对象调用的wait方法后的线程。
  • .wait方法与notify方法必须要在同步代码块或者是同步函数中使用。因为:必须要通过锁对象调用这2个方法。

线程池

是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源。
好处

  • 降低资源消耗。减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
  • 提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。
  • 提高线程的可管理性。可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下。

方法

  • JDK1.5之后提供线程池的顶级接口Executor,也是线程池的工厂类,用来生成线程池。
  • 静态方法:public static ExecutorService newFixedThreadPool(int nThreads) 返回线程池对象。(创建的是有界可重用线程池,也就是池中的线程个数可以指定最大数量)
  • ExecutorService线程池接口,其中submit(Runnable task) :方法获取线程池中某一个线程对象,并执行;void shutdown() 方法关闭/销毁线程池。

线程池使用步骤

  • 使用线程池工厂类Executor里提供的静态方法newFixedThreadPool生产一个指定线程数量的线程池。
  • 创建一个类,实现Runnable接口,重写run方法,设置线程任务。
  • 调用ExecutorService中的方法submit,传递线程任务(实现类),开启线程,执行run方法。(线程池会一直开启,使用完线程,会把线程归还线程池,供下次使用)
  • 调用ExecutorService中的方法shutdown销毁线程池。(不建议执行)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值