Presentation is loading. Please wait.

Presentation is loading. Please wait.

2018/12/7 Java语言程序设计-多线程 教师:段鹏飞.

Similar presentations


Presentation on theme: "2018/12/7 Java语言程序设计-多线程 教师:段鹏飞."— Presentation transcript:

1 2018/12/7 Java语言程序设计-多线程 教师:段鹏飞

2 1、进程和线程的区别 2、Thread和Runnable的区别 3、能够使用Thread或Runable创建线程 4、如何进行线程同步
2018/12/7 知识点 1、进程和线程的区别 2、Thread和Runnable的区别 3、能够使用Thread或Runable创建线程 4、如何进行线程同步

3 1958年,麦卡锡提出问题:A输入一个命令,需要10秒,电脑只需要1秒,电脑大部分时间在等待...
多用户多进程

4 多核时代的多进程

5 界面卡死

6 1、进程与线程的概念 2、Java中多线程的编程 3、线程的同步与死锁 主要内容 继承Thread类与使用Runnable接口

7 计算机的核心是CPU,它承担了所有的计算任务。它就像一座工厂,时刻在运行。
进程与线程的区别 计算机的核心是CPU,它承担了所有的计算任务。它就像一座工厂,时刻在运行。

8 假定工厂的电力有限,一次只能供给一个车间使用。也就是说,一个车间开工的时候,其他车间都必须停工。背后的含义就是,单个CPU一次只能运行一个任务。

9 进程 进程就好比工厂的车间,它代表CPU所能处理的单个任务。任一时刻,CPU总是运行一个进程,其他进程处于非运行状态。

10 调度策略 Java的调度方法 进程的调度 时间片 抢占式:高优先级的进程抢占CPU 同优先级线程组成先进先出队列,使用时间片策略
对高优先级,使用优先调度的抢占式策略 1 2

11 一个车间里,可以有很多工人。他们协同完成一个任务。

12 线程就好比车间里的工人,一个进程可以包括多个线程。

13 线程共享 车间的空间是工人们共享的,比如许多房间是每个工人都可以进出的。这象征一个进程的内存空间是共享的,每个线程都可以使用这些共享内存。

14 多线程

15 可是,每间房间的大小不同,有些房间最多只能容纳一个人,比如厕所。里面有人的时候,其他人就不能进去了。这代表一个线程使用某些共享内存时,其他线程必须等它结束,才能使用这一块内存。

16 一个防止他人进入的简单方法,就是门口加一把锁。先到的人锁上门,后到的人看到上锁,就在门口排队,等锁打开再进去。这就叫"互斥锁"(Mutual exclusion,缩写 Mutex),防止多个线程同时读写某一块内存区域。

17 还有些房间,可以同时容纳n个人,比如厨房。也就是说,如果人数大于n,多出来的人只能在外面等着。这好比某些内存区域,只能供给固定数目的线程使用。

18 这时的解决方法,就是在门口挂n把钥匙。进去的人就取一把钥匙,出来时再把钥匙挂回原处。后到的人发现钥匙架空了,就知道必须在门口排队等着了。这种做法叫做"信号量"(Semaphore),用来保证多个线程不会互相冲突。 不难看出,mutex是semaphore的一种特殊情况(n=1时)。也就是说,完全可以用后者替代前者。但是,因为mutex较为简单,且效率高,所以在必须保证资源独占的情况下,还是采用这种设计。

19 程序 进程 进程的特点 进程和线程 程序是一段静态的代码,它是应用程序执行的蓝本 进程是指一种正在运行的程序,有自己的地址空间 动态性
并发性 独立性

20 进程和线程 线程的定义 进程内部的一个执行单元,它是程序中一个单一的顺序控制流程。如果在一个进程中同时运行了多个线程,用来完成不同的工作,则称之为多线程

21 进程与多线程

22 进程与线程 什么时候用进程,什么时候用线程? ——多线程是十字路口 多进程是立交桥。

23 多线程的优势 多线程使系统空转时间减少,提高CPU利用率 进程间不能共享内存,但线程之间共享内存非常容易 使用多线程实现多任务并发比多进程的效率高

24 线程要经历创建、就绪、运行、阻塞和死亡等5个状态 ,称为生命周期。
线程的生命周期 线程要经历创建、就绪、运行、阻塞和死亡等5个状态 ,称为生命周期。

25 2 线程的使用方法 1、创建Thread子类构造线程 2、实现Runnable接口构造线程

26 两种方法来创建线程 线程的创建和启动 继承Java.lang.Thread类,并覆盖run() 方法
实现Java.lang.Runnable接口,并实现run() 方法 class MyThread extends Thread { public void run( ) { /* 覆盖该方法*/ } class MyThread implements Runnable{ public void run( ) { /* 实现该方法*/ }

27 启动线程 线程的创建和启动 新建的线程不会自动开始运行,必须通过start( )方法启动 启动继承Thread的线程
启动实现Runnable接口的线程 MyThread t = new MyThread (); t.start(); MyThread mt = new MyThread (); Thread t = new Thread(mt); t.start();

28 继承Java.lang.Thread类 线程的创建和启动 public class ThreadDemo1 {
public static void main(String args[]) { MyThread1 t = new MyThread1(); t.start(); while (true) { System.out.println("兔子领先了,别骄傲"); } class MyThread1 extends Thread { public void run() { System.out.println("乌龟领先了,加油"); Java程序启动时,会立刻创建主线程,main就是在这个线程上运行。当不再产生新线程时,程序是单线程的 演示示例:创建和启动多线程

29 实现Java.lang.Runnable接口
线程的创建和启动 实现Java.lang.Runnable接口 public class ThreadDemo2 { public static void main(String args[]) { MyThread2 mt = new MyThread2(); Thread t = new Thread(mt); t.start(); while (true) { System.out.println("兔子领先了,加油"); } class MyThread2 implements Runnable { public void run() { System.out.println("乌龟超过了,再接再厉"); 演示示例:创建和启动多线程

30 两种线程创建方式的比较 线程的创建和启动 继承Thread类方式的多线程 实现Runnable接口方式的多线程 优势:编写简单
劣势:无法继承其它父类 实现Runnable接口方式的多线程 优势:可以继承其它类,多线程可共享同一个Thread对象 劣势:编程方式稍微复杂,如果需要访问当前线程,需要调用Thread.currentThread()方法

31 线程的创建与启动 创建Thread子类构造线程 (1)创建一个Thread类的子类;
(2)在子类中重新定义自己的run()方法,这个中包含了线程要实现的操作; (3)用关键字new 创建一个线程对象; (4)调用start()方法启动线程。

32 3、构造线程:Thread(Runnable对象名); 4、启动线程:线程对象.start( );

33 Thread类的常用方法 线程的创建和启动 方 法 功 能 static Thread currentThread()
得到当前线程 final String getName( ) 返回线程的名称 final void setName(String name) 将线程的名称设置为由name指定的名称 void start( ) 调用run( )方法启动线程,开始线程的执行 void run( ) 存放线程体代码

34 新生 可运行 阻塞 死亡 线程的状态 使用new关键字创建一个线程后,尚未调用其start方法之前 调用线程对象的start方法之后
这个状态当中,线程对象可能正在运行,也可能等待运行 阻塞 一种“不可运行”的状态,在得到一个特定的事件之后会返回到可运行状态 死亡 线程的run方法运行完毕或者在运行中出现未捕获的异常时

35 线程同步的必要性

36 使用多线程进行开发,让两个用户同时操作一个银行账户。每次取款100元,取款前先检查余额是否足够。如果不够,放弃取款
线程同步的必要性 使用多线程进行开发,让两个用户同时操作一个银行账户。每次取款100元,取款前先检查余额是否足够。如果不够,放弃取款 创建银行账户类Account 创建取款线程TestAccount 创建测试类TestWithdrawal,让两个用户同时取款

37 当多个线程访问同一个数据时,容易出现线程安全问题。需要让线程同步,保证数据安全
线程同步的必要性 当多个线程访问同一个数据时,容易出现线程安全问题。需要让线程同步,保证数据安全 线程同步 当两个或两个以上线程访问同一资源时,需要某种方式来确保资源在某一时刻只被一个线程使用 线程同步的实现方案 同步代码块 同步方法

38 在Java中,每个对象有一个“互斥锁”,该锁可用来保证在同一时刻只能有一个线程访问该对象。 锁的使用过程(当一个线程要操作一个对象时)
线程的同步与互斥 对象互斥锁 在Java中,每个对象有一个“互斥锁”,该锁可用来保证在同一时刻只能有一个线程访问该对象。 锁的使用过程(当一个线程要操作一个对象时) 准备 加锁 对象是否 已加锁 进入 临界区 执行操作 解锁

39 线程同步的实现 可以是任何存在的对象 synchronized(obj){ //此处代码为同步代码块 } 同步的代码内容

40 线程同步的实现

41 线程同步的实现 访问修饰符 synchronized 返回类型 方法名{ }

42 死锁 线程同步的好处 线程同步的缺点 死锁 解决了线程安全问题 性能下降 会带来死锁 当两个线程相互等待对方释放“锁”时就会发生死锁
出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续 多线程编程时应该注意避免死锁的发生

43 练习——线程同步 需求说明: 使用线程同步实现两个用户同时安全操作一个银行账户

44 生产者和消费者问题 线程间通信 假设仓库中只能存放一件产品,生产者将生产出来的产品放入仓库,消费者将仓库中产品取走消费
如果仓库中没有产品,则生产者将产品放入仓库,否则停止生产并等待,直到仓库中的产品被消费者取走为止 如果仓库中放有产品,则消费者可以将产品取走消费,否则停止消费并等待,直到仓库中再次放入产品为止

45 线程的同步与互斥 线程间需协调与通讯:生产者/消费者问题 进队 出队 生产者 消费者

46 这是一个线程同步问题,生产者和消费者共享同一个资源,并且生产者和消费者之间相互依赖,互为条件
线程间通信的必要性 这是一个线程同步问题,生产者和消费者共享同一个资源,并且生产者和消费者之间相互依赖,互为条件 对于生产者,没有生产产品之前,要通知消费者等待。而生产了产品之后,又需要马上通知消费者消费 对于消费者,在消费之后,要通知生产者已经消费结束,需要继续生产新产品以供消费 在生产者消费者问题中,仅有synchronized是不够的 synchronized可阻止并发更新同一个共享资源,实现了同步 synchronized不能用来实现不同线程之间的消息传递(通信)

47 Java提供了3个方法解决线程之间的通信问题
线程间通信的必要性 Java提供了3个方法解决线程之间的通信问题 方法名 作 用 final void wait() 表示线程一直等待,直到其它线程通知 void wait(long timeout) 线程等待指定毫秒参数的时间 final void wait(long timeout,int nanos) 线程等待指定毫秒、微妙的时间 final void notify() 唤醒一个处于等待状态的线程 final void notifyAll() 唤醒同一个对象上所有调用wait()方法的线程,优先级别高的线程优先运行 均是java.lang.Object类的方法 都只能在同步方法或者同步代码块中使用,否则会抛出异常

48 定义产品类 线程间通信的实现 class SharedData{ private char c;
private boolean isProduced = false; // 信号量 public synchronized void putShareChar(char c) { // 如果产品还未消费,则生产者等待 if (isProduced) { try{ System.out.println("消费者还未消费,因此生产者停止生产"); wait(); // 生产者等待 } catch (InterruptedException e) {e.printStackTrace(); } } this.c = c; isProduced = true; // 标记已经生产 notify(); // 通知消费者已经生产,可以消费 System.out.println("生产了产品" + c + " 通知消费者消费..."); public synchronized char getShareChar() { // 如果产品还未生产,则消费者等待 if (!isProduced){ try{ System.out.println("生产者还未生产,因此消费者停止消费"); wait(); // 消费者等待 } catch (InterruptedException e) {e.printStackTrace();} isProduced = false; // 标记已经消费 notify(); // 通知需要生产 System.out.println("消费者消费了产品" + c + " 通知生产者生产..."); return this.c; 线程间通信的实现 定义产品类

49 定义生产者线程类和消费者线程类 线程间通信的实现 //生产者线程 class Producer extends Thread {
private SharedData s; Producer(SharedData s){ this.s = s; } public void run(){ for (char ch = 'A'; ch <= 'D'; ch++){ try{ Thread.sleep((int) (Math.random() * 3000)); } catch (InterruptedException e) { e.printStackTrace(); s.putShareChar(ch); // 将产品放入仓库 //消费者线程 class Consumer extends Thread { private SharedData s; Consumer(SharedData s){ this.s = s; } public void run(){ char ch; do { try { Thread.sleep((int)(Math.random()*3000)); } catch (InterruptedException e) { e.printStackTrace(); ch = s.getShareChar(); // 从仓库中取出产品 } while (ch != 'D');

50 线程间通信的实现3-3 定义测试类 //测试类 class CommunicationDemo{
public static void main(String[] args){ //共享同一个共享资源 SharedData s = new SharedData(); //消费者线程 new Consumer(s).start(); //生产者线程 new Producer(s).start(); } 演示示例:使用多线程实现生产者消费者问题

51 Java中实现线程通信的三个方法的作用是什么?
总结 进程和线程有什么联系和区别? 创建线程的两种方式分别是什么? 如何实现线程同步? Java中实现线程通信的三个方法的作用是什么?

52 2018/12/7 谢谢


Download ppt "2018/12/7 Java语言程序设计-多线程 教师:段鹏飞."

Similar presentations


Ads by Google