多线程知识点

1.Java多线程和并发编程

多线程和多进程简介

多进程概念

  • 当前操作系统都是多任务OS
  • 每个独立执行的任务就是一个进程
  • OS将时间划分为多个时间片(时间很短)
  • 每个时间片将CPU分配给某个任务,时间片结束,CPU将自动回收,再分配给另外任务。从外部来看,所有任务是同时在进行。但是在CPU上,任务是按照串行依次运行(单核CPU)。如果是多核,多个进程任务可以并行。单核上,多进程只能串行操作。
多进程的优点
  1. 可以同时运行多个任务
  2. 程序因IO堵塞时,可以释放CPU,让CPU为其他程序服务(提高CPU利用率),让CPU为其他程序提供服务
  3. 当系统有多个CPU时,可以为多个程序同时服务
    1. CPU的频率不再提高,而是提高核数
多进程缺点
  • 太笨重,不好管理,不好切换

多线程概念

  • 一个程序可以包括多个子任务,可串/并行
  • 每个子任务可以称为一个线程
  • 如果一个子任务阻塞,程序可以将CPU调度另外一个子任务进行工作。这样CPU还是保留在本程序中,而不是被调度到别的程序(进程)去,这样,提高本程序所获得CPU时间和利用率。

多进程和多线程的区别

  • 线程共享数据
  • 线程通讯更高效
  • 线程更轻量级,更容易切换
  • 多个线程更容易管理

2.Java多线程的实现

多线程的创建有两种方式

java.lang.Thread

线程继承Thread类,实现run方法

java.lang.Runnable

线程实现Runnable接口,实现run方法

Java的四个主要接口:

Clonable:用于对象克隆

Comparable:用于对象比较

Serializable:用于对象序列化

多线程启动

  • star方法,会自动以新进程调用run方法
  • 直接调用run方法,将会变成串行执行
  • 同一个线程,多次star会报错,只执行一次star方法
  • 多个线程启动,其启动顺序是随机的
  • 线程无需关闭,只要其run方法执行结束后,自动关闭
  • main函数(线程)可能早于新线程结束,整个程序并不终止
  • 整个程序终止是等所有的线程都终止(包括main函数线程)

多线程实现对比

Thread和Runnable

  1. Thread占据了父类名额,不如Runnable方便
  2. Thread类实现Runnable
  3. Runnable启动时需要Thread类的支持
  4. Runnable更容易实现多线程资源共享

Runnable方式:

  1. 通过实现Runnable接口来创建线程

  2. 实现Runnable的对象必须包装在Thread类里面,才可以启用

在这里插入图片描述

  1. 通过start方法来启动线程的run方法

3.多线程信息共享

  • 线程类
    • 通过继承Thread或实现Runnable方法
    • 通过start方法,调用run方法,run方法工作
    • 线程run结束后,线程退出
  • 粗粒度:子线程与子线程之间、和main线程之间缺乏交流
  • 细粒度:线程之间有信息交流通讯
    • 通过共享变量达到信息共享
    • JDK原生库暂不支持发送消息(类似MPI并行库直接发送消息)

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

static变量

同一个Runnable类的成员变量

在这里插入图片描述

多线程信息共享问题

  • 工作缓存副本

  • 关键步骤缺乏枷锁限制(在买票系统中卖出门票后票数减一就是关键步骤)

  • 例如 i++,并非原子性操作

    • 读取主存i(正本)到工作缓存中(副本)中
    • 每个CPU执行(副本)i+1操作
    • CPU将结果写入到缓存(副本)中
    • 数据从工作缓存(副本)刷到主存(正本)中

在这里插入图片描述

线程只依赖于工作缓存

变量副本解决问题的方法

-采用volatile关键字修饰变量

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

关键步骤枷锁限制

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

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

-互斥时同步的一种特例

互斥的关键字时synchronized

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

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

volatile实例代码:

public class ThreadDemo2{
    public static void main(String args[]) throws Exception{
        TestThreath2 t = new TestThread2();
        t.start();
        Thread.sleep(2000);
        t.flag = false;
        System.out.println("main thread is exiting");
    }
}

class TestThread2 extend Thread{
    volatile boolean flag = ture; //用volatile修饰的变量可以及时在各线程里面通知
    public void run(){
        int i = 0;
        while(true){
            i++;
        }
        System.out.println("test thread3 is exiting");
    }
}

volatile修饰的变量,一旦被修改,所有的线程是可以立刻发现的;

synchronized实例代码:

public class ThreadDemo3{
    public static void main(String[] args){
        TestThread3 t = new TestThread3();
        new Thread(t,"Thread-0").start();
        new Thread(t,"Thread-1").start();
        new Thread(t,"Thread-2").start();
    } 
}
class TestThread3 implements Runnable{
    private volatile int tickets = 100;//多个线程共享数据
    String str = new String("");
    
    public void run(){
        while(true){
            sale();
            try{
                Thread.sleep(100);
            }catch(Exception e){
                System.out.println(e.getMessage());
            }
            if(tickets <= 0){
                break;
            }
        }
    }
    public synchronized void sale(){ //同步函数
        if(tickets>0){
            System.out.println(Thread.currentThread().getName() + "is saling ticket" + tickets--);
        }
    }
}

在这里插入图片描述

synchronized加锁必须加在某一个对象上,只要变量不为空;可以修饰代码块,也可以修饰函数。

4. Java多线程管理

线程状态

NEW刚创建(new)

RUNNABLE就绪态(start)

RUNNING运行中(run)

BLOCK阻塞(sleep)

TERMINATED结束

在这里插入图片描述

  • Thread的部分API已经废弃
    • 暂停和恢复 suspend/resume
    • 消亡 stop/destroy
  • 线程阻塞/和唤醒
    • sleep,时间一到,自己会醒来
    • wait/notify/notifyAll,等待,需要别人来唤醒
    • join,等待另外一个线程结束
    • interrupt ,向另外一个线程发送中断信号,该线程接收到信号,会触发InterruptedException(可解除阻塞),并进行下一步处理

例:生产者消费者问题

线程被动地暂停和终止

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

-没有及时释放资源

线程主动暂停和终止

-定期监测共享变量

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

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

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

interrupted()是Thread类的方法,用来测试当前线程是否收到一个INTERRUPT的信号。如果收到,该方法返回true,否则返回false;而interrupted默认值为false。

多线程死锁

-每个线程互相持有别人需要的锁

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

//Time是JDK5引入的新类,位于java.util.concurrent包中。它提供了时间单位粒度和一些时间转换、计时和延迟等函数。

守护后台线程

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

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

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

总结

  • 了解线程的多个状态
  • 了解线程协作机制
  • 线程协作机制尽量简单化,采用粗粒度协作
  • 了解死锁和后台线程概念
  • 使用jvisualvm查看线程情况
  • 尽量使用定时监控变量的方式来进行自我状态控制
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值