1 线程运行原理

a.流程图:讲义当中的彩色图。

b.内存图:栈内存线程独立,堆内存线程共享。

6.1线程与同步

2.使用继承类的方式创建多线程

定义一个类,然后继承Thread

覆盖重写run方法

6.1线程与同步

调用start启动线程

6.1线程与同步

3.继承类的Thread成员方法

public String getName():获取线程的名称

public void start():启动一个线程,会瞬间完成的。

public void run():指定线程的任务内容

public static Thread currentThread():获取当前线程

public static void sleep(long time):睡眠指定毫秒时长

6.1线程与同步

 

Thread类还有两个构造方法:

public Thread(Runnable target):创建一个线程,参数代表线程的任务内容。
public Thread(Runnable target, String name):创建一个线程,第二个参数代表线程的名称。

 

4.通过一个接口调用run方法:Runnable接口

使用实现接口的方式创建多线程

         . 定义一个类,实现Runnable接口

           覆盖重写run方法

         . 创建一个线程,使用Runnable作为构造参数。

         . 调用start启动线程。

6.1线程与同步

接口方式的好处:

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

 

1. 适合多个相同的程序代码的线程去共享同一个资源。

2. 可以避免java中的单继承的局限性。

3. 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和数据独立。

4. 线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类。

 

Runnable接口的使用步骤:

1. 定义一个实现类,实现Runnable接口。

2. 实现类必须覆盖重写run方法。

3. 创建一个Runnable实现类对象,作为Thread构造参数。

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



启动线程的两种方式,效果一样。

1. 继承Thread类,覆盖重写run方法。

2. 实现Runnable接口,覆盖重写run方法,然后再作为Thread构造参数

 

5.匿名内部类:在这里其实就是一个runnable接口;

匿名内部类的三种使用场景:



(1). 接口可以使用匿名内部类,需要覆盖重写抽象方法。

(2). 抽象类也可以使用匿名内部类,需要覆盖重写抽象方法,或者普通方法也行。

(3). 普通类也可以使用匿名内部类,只要不是final的,就行。

6.1线程与同步

 

6.1线程与同步

6.线程安全:模拟场景-卖电影票

为什么抢票的结果会出现一个负值或者一个重复值?

哒:本来拆开的动作,被第三者插足。

哒:1.因为买票有两个动作:a.检查>0;   b.出票  

2.还有可能出现相同的数字,因为“后。。”并非原子性操作,

a.先取原来本来的值  b.向下

这两个动作中间也有可能被其他线程插足。

7.解决问题:

上锁:在同一时刻智能允许一个人进去。

本来是抢占票的问题,现在换成一个抢锁的问题。

使用方式:1.同步代码块,

        2.同步方法

          3.lock接口

8.同步代码块:

小括号当中必须是一个引用类型,不能是基本类型。

含义:

只要执行到了sync这一行,那么就会尝试霸占锁对象。

如果霸占成功,那么就进入大括号执行内容。

如果霸占失败,将会卡死在sync这一行,等待正在用的人释放锁,我才能重新抢这个锁。

如果执行离开了大括号范围,那么将会自动释放锁。

6.1线程与同步

6.1线程与同步

9.同步方法:

同步方法的格式:

修饰符 synchronized 返回值类型 方法名称(参数列表) {

    方法体

}

 

6.1线程与同步

6.1线程与同步10.Lock接口:

获取锁,释放锁.

java.util.concurrent.locks.Lock接口:



1. 创建一个全局唯一的Lock接口对象:Lock lock = new ReentrantLock();

2. 获取锁:.lock(),如果抢锁成功,那么就会继续执行;如果抢锁失败,那么将会卡死在这一行。

3. 释放锁:.unlock(),释放锁。

6.1线程与同步

6.1线程与同步

 

11.线程的6种状态:

new、

Runnable、

blocked:挠门等待的状态-锁阻塞

waiting、平静的等待(经过协商过的等待)

timed-waiting、

termintted、

  1. NEW(新建) 线程刚被创建,但是并未启动。
  2. Runnable(可运行)

线程可以在java虚拟机中运行的状态,可能正在运行自己代码,也可能没有,这取决于操作系统处理器。

  1. Blocked(锁阻塞)

当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状态;当该线程持有锁时,该线程将变成Runnable状态。

  1. Waiting(无限等待)

一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入Waiting状态。进入这个状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAll方法才能够唤醒。

  1. Timed Waiting(计时等待)

同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。这一状态将一直保持到超时期满或者接收到唤醒通知。带有超时参数的常用方法有Thread.sleep 、Object.wait。

  1. Teminated(被终止)

因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡。

 

12.与waitting状态的两个方法

public void wait():当前线程主动释放锁,进入WAITING无限平静等待,死等。等待别人通知我,我再继续。

public void notify()通过锁调用,通知在锁上处于等待状态的人,让其结束等待。

这两个方法是一对儿,必须通过同一个锁进行调用,必须在同步代码范围之内调用。

6.1线程与同步

6.1线程与同步

wait方法的重载形式:



public void wait(long time):主动释放锁,进入TIMED_WAITING状态,定时等待,最多等待指定的毫秒时长。

如果在此期间之内,收到了通知,那么将会结束等待。

如果超过了指定的时间,仍然没有通知,我也会结束等待。

6.1线程与同步

6.1线程与同步

13sleep的意义:

sleep方法只是让线程睡一会儿,与所竞争无关。不会释放锁,也不会抢锁。

这个方法也会导致进入TIMED_WAITING状态,但是原理与wait(long)不同。

【sleep与锁无关】,wait会释放锁。

6.1线程与同步

14.补充知识点:

 (1)jvm虚拟机的线程转换状态图。

也叫状态机图

6.1线程与同步

(2) 问题:

请描述Thread类中的start()方法与run()方法的区别。

da:

线程对象调用run()方法不开启线程,仅是对象调用方法。

线程对象调用start()方法开启线程,并让jvm调用run()方法在开启的线程中执行。

 

(3) 创建线程的两种方式。

da:

  1. 第一种方式是将类声明为 Thread 的子类。
  1. 定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务,因此把run()方法称为线程执行体。
  2. 创建Thread子类的实例,即创建了线程对象。
  3. 调用线程对象的start()方法来启动该线程。

 

  1. 第二种方式是声明一个类实现Runnable 接口。

1. 定义Runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。

2. 创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,Thread对象才是真正的线程对象。

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

 

相关文章:

  • 2021-09-02
  • 2021-08-12
  • 2022-01-21
  • 2021-09-30
  • 2022-12-23
  • 2021-11-18
  • 2021-10-11
猜你喜欢
  • 2021-11-18
  • 2021-11-18
  • 2021-08-29
  • 2021-12-20
  • 2022-12-23
  • 2021-11-20
  • 2021-07-05
相关资源
相似解决方案