第十三章 多线程并发

第一节 多进程和多线程简介

当前的操作系统都是多任务os

每个独立执行的任务就是一个进程

OS将时间划分为多个时间片(时间很短)

每个时间片内将CPU分配给某一个任务,时间片结束,CPU将自动回收,再分配给另外任务。从外部看,所有任务是同时在执行。但是在CPU上,任务是按照串行依次运行(单核CPU)。如果是多核,多个进程任务可以并行。但是单个核上,多进程只能串行执行。

多进程的优点:

- 可以同时运行多个任务

- 程序因IO堵塞时,可以释放CPU,让CPU为其他程序服务

- 当系统有多个CPU时,可以为多个程序同时服务

多进程的缺点:

- 不好管理

- 不好切换

一个程序可以包括多个子任务,可串/并行。

每个子任务称为一个线程。

如果一个子任务阻塞,程序可以将CPU调度另外一个子任务进行工作。这样CPU还是保留在本程序中,而不是被调度到别的程序中。这样可以提高本程序所获得的CPU时间和利用率。

多进程 vs 多线程:

- 线程共享数据

- 线程通讯更搞笑

- 线程更轻量级,容易切换

- 多个线程更容易管理


第二节 多线程实现

多线程创建:

- java.lang.Thread: 线程继承Thread类,实现run方法

- java.lang.Runnable接口:线程实现Runnable接口,实现run方法

public class Thread1 extends Thread{
    public void run(){
        System.out.println(“hello”);
    }
}

public class Thread2 implements Runnable{
     public void run(){
        System.out.println(“hello”);
    }
}

启动:

- start方法,会自动以新进程调用run方法

- 直接调用run方法,将变成串行执行

- 同一个线程,多次start会报错,只执第一次start方法

- 多个线程启动,其启动的先后顺序是随意的

- 线程无需关闭,只要其run方法执行结束后,将自动关闭

- main函数(线程)可能早于新线程结束,整个程序并不终止

- 整个程序终止是等所有的线程都终止(包括main函数线程)

Thread vs Runnable

- Thread占据了父类的名额,不如Runnable方便

- Thread类实现Runnable

- Runnable启动时需要Thread类的支持

- Runnable更容易实现多线程中资源共享

- 结论:建议实现Runnable接口来完成多线程


第三节 多线程信息共享

线程类:

- 通过继承Thread或实现Runnable

- 通过start方法,调用run方法,run方法工作

- 线程run结束后,线程退出

粗粒度:子线程与子线程之间,和main线程之间缺乏交流

细粒度:线程之间有信息交流通讯

- 通过共享变量达到信息共享

- JDK原生库暂不支持发送信息(类似MPI并行库直接发送消息)

通过共享变量在多个线程中共享消息:

- static变量

- 同一个Runnable类的成员变量

public class ThreadDemo0{
    public static void main(String [] args){
        new TestThread0().start();
        new TestThread0().start();
        new TestThread0().start();
        new TestThread0().start();
    }
}

class TestThread0 extends Thread{
    private int tickets = 100;        //每个线程卖100张,没有共享
    private static int tickets = 100; //static变量是共享的,所有的线程共享
    public void run(){
        while(true){
            卖一张票
        }
    }
}

多线程信息共享问题:

- 工作缓存副本

- 关键步骤缺乏加锁限制(一次只能有一个人修改他)

i++, 并非原子性操作

- 读取主存i(正本)到工作缓存(副本)中

- 每个CPU执行(副本)i+1操作

- CPU将结果写到缓存(副本)中

- 数据从工作缓存(副本)刷到主存(正本)中

变量副本问题的解决方法:

- 采用volatile关键字修饰变量

- 保证不同线程对共享变量操作时对可见性

关键步骤加锁限制:

- 互斥:某一个线程运行一个代码段(关键区),其他线程不能同时运行这个代码段

- 同步:多个线程的运行,必须按照某一种规定的先后顺序来运行

- 互斥是同步的一种特例

互斥的关键字是synchronized:

- synchronized代码块/函数,只能一个线程进入

- synchronized加大性能负载,但是使用简便


第四节 Java多线程管理(1)

· 等待

· 通知/唤醒

· 终止

线程状态:

- NEW 刚创建(new)

- RUNNABLE 就绪态(start)

- RUNNING 运行中(run)

- BLOCK 阻塞(sleep)

- TERMINATED 结束

Thread的部分API已经废弃:

- 暂停和恢复 suspend/resume

- 消亡 stop/destory

线程阻塞/和唤醒:

- sleep,时间一到,自己会醒来

- wait/notify/notifyAll, 等待,需要别人来唤醒

- join,等待另外一个线程结束

- interrupt,向另外一个线程发送中断信号,该线程收到信号,会触发InterruptedException(可接触阻塞),并进行下一步处理


第四节 Java多线程管理(2)

线程被动地暂停和终止:

- 依靠别的线程来拯救自己

- 没有及时释放资源

线程主动暂停和停止:

- 定期监测共享变量

- 如果需要暂停或者终止,先释放资源,再主动动作

- 暂停:Thread.sleep(), 休眠

- 终止:run方法结束,线程终止

多线程死锁:

- 每个线程互相持有别人需要的锁(哲学家吃面)

- 预防死锁,对资源进行等级排序

守护(后台)线程

- 普通线程的结束,是run方法运行结束

- 守护线程的结束,是run方法运行结束,或main函数结束

- 守护线程永远不要访问资源,如文件或数据库等

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值