java基础新学——多线程

多线程

1. 理解什么是多任务

  • 同一时间同时干多件事情

2. 并发问题案例

  • 案例1:购买火车票问题,总票数为10,若同时有12个人在同一时间购票,并且显示购票成功,但实际情况有2人未购票成功。
//买火车票例子
private int ticketNums = 10;

@Override
public void run(){
    while(true) {
        if (ticketNums<=0){
            break;
        }
        try {
            //模拟延迟
            Threand.sleep();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //票数的减少
  		System.out.println(Thread.currentThread().getName()+tickNums--);
    }
}

public static void main(String[] args) {
    TestThread ticket = new TestThread();
    
    new Thread(ticket,"test1").start();
    new Thread(ticket,"test2").start();
    new Thread(ticket,"test3").start();
}

//结果出现问题,出票顺序出现混乱
//注意该类实现runnable接口
  • 案例2:龟兔赛跑问题
//模拟龟兔赛跑
   
//重写run方法
public void run() {
    for (int i = 0; i < 100; i++) {
        //模拟兔子睡觉
        if (Thread.currentThread().getName().equals("兔子") && i%10 == 0) {
            try {
                Thread.sleep(10);
            } catch (InteruptedException e) {
                e.printStackTrace();
            }
        }
        
       //判断比赛是否结束
 		boolean flag = gameOver(i);
 		if (flag){
            break;
        }       
        System.out.println(Thread.currentThread().getName+i)
    }
}

//胜利者
private static String winner;

//判断是否有胜利者
public Boolean gameOver(int steps) {
    if (winner!=null){
    	return true;
    }else {
        if (steps >= 100){
            winner = Thread.currentThread().getName();
            System.out.println(winner);
            return true;
        }
    }
    return false;
}


//测试
new Treand(race,"兔子").start();
new Thread(race,"乌龟").start();

//注意该类实现runnable接口

3. 线程

3.1 基础知识
  • 线程由cpu进行调度,具体执行顺序由cpu决定
  • 线程分为用户线程守护线程
  • 虚拟机必须确保用户线程执行完毕
3.2 三种线程创建方法
  • 继承Thread类
    • 自定义线程类并继承Thread类
    • 重写run()方法
    • 调用start()开启线程
  • 实现Runnable接口(推荐)
    • 自定义线程类并继承Runnable接口
    • 重写run()方法
    • 执行线程,丢入接口实现类,调用start()开启线程
    • 推荐使用:避免单继承局限性,方便同一个对象被多个线程使用
  • 实现Callable接口
    • 创建服务,设置线程池数量
    • 执行方法
    • 获取结果
    • 关闭服务
  • 可以定义返回值,可以抛出异常
3.3 线程操作
  • 线程停止

    • 建议正常停止,利用次数
    • 利用标志位,线程运行前进行标志位判断
    • 不要使用stop或者是destroy方法
  • 线程休眠

    • sleep函数:指定当前线程阻塞的毫秒数
    • sleep存在异常InterruptedException
    • sleep时间打倒后线程进入就绪状态
    • sleep可以模拟网络延迟(放大问题的发生性),倒计时等
    • 每一个对象都有一个锁,sleep不会释放锁
    //利用sleep模拟计时
    int num = 10;
    while (true){
        Thread.sleep(1000);
        System.out.println(num--);
        if (num<=0){
            break;
        }
    }
    
    //打印系统当前时间
    //获取系统当前时间
    Date startTime = new Date(System.out.currentTimeMillis());
    while (true){
        try {
            Thread.sleep(1000);
            System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));
            startTime = new Date(System.out.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
  • 线程礼让Yield

    • 将线程从运行状态转换为就绪状态
    • 让正在执行的线程暂停,但不阻塞
    • 案例伪代码
    Thread.yield();
    
  • Join线程合并

    • 优先执行当前线程,其它线程阻塞
    • 伪代码
    thread.join();//优先执行thread对象
    
  • 线程状态观测

    • 伪代码
    //state为观测状态结果,thread为执行线程
    Thread.State state = thread.getState();
    
    • 注意:死亡之后的线程无法再次启动
    • 线程状态图

    mark

  • 线程优先级

    • main方法默认优先级为5
    • 设置优先级
    thread.setPriority(a);
    //a为级别,取值范围:1-10
    
    • 获取优先级
    thread.getPriority();
    
  • 守护线程(daemon)

    • 如后台记录擦操作日志,监控内存,垃圾回收等待
    • 虚拟机不用等待守护线程执行完毕
3.4 线程同步问题
  • 队列机制

  • synchronized锁机制

    • 线程获得对象的排它锁,独占资源,其它资源等待
    • 缺点
      • 引起上下文切换和调度延迟,引起性能问题。
      • 性能导致问题
    • synchronized同步方法
    • synchronized同步块
    • 锁的对象就是变化的量
  • 线程同步不安全案例

    • 不安全的买票
    • 不安全的取钱
    • List中添加数据
    for (int i = 0; i < 1000; i++) {
        new Thread(()->{
            sysnchronized (list){
                list.add(Thread.currentThread()/getName());
            }
        })
    }
    //也可以直接用CopyOnWriteArrayList,是线程安全的
    
3.5 死锁
  • 产生死锁的四个必要条件
    1. 互斥条件:一个资源每次只能被一个进程使用。
    2. 请求与保持条件:一个进程因请求资源而阻塞时,对以获得的资源保持不放。
    3. 不剥夺条件:进程以获得的资源,在未使用完之前,不能强行剥夺。
    4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源。
  • 如何避免
    • 对于产生死锁的必要条件,破坏任意一个或多个
3.6 Lock锁
  • 显示定义同步锁

  • Lock只有代码块锁

  • 相对于synchronized性能更好

  • 利用ReentranLock(可重复锁)实现,可以显示加锁,释放锁

    //伪代码
    //定义锁
    private final ReentrantLock lock = new ReentrantLock();
    //使用
    lock.lock();//加锁
    lock.unlock();//解锁
    
3.7 线程协作
  • 生产者和消费者问题
    • 对于生产者:没有产品,通知消费者等待;有产品,通知消费者消费。
    • 对于消费者:消费之后,通知生产者已结束消费,需再次生产。
  • 线程通信问题
    • 管程法:增加缓冲区
    • 信号灯法:通过标志位来解决
3.8 线程池
  • 背景:并发情况下多线程对性能影响很大。

  • 思路:提前创建好相关线程

  • 好处:

    • 提高响应速度
    • 降低资源消耗,重复利用,无需多次创建
    • 便于线程管理
  • 使用

    • Executors工具类:用于创建并返回不同类型的线程池
    //创建线程池,a为线程池大小
    ExcutotService service = Executors.newFixedThreadPool(a);
    //执行线程
    service.execute();    
    //关闭连接    
    service.shutdown();
    

感谢狂神老师的视频教学,特别说明,资料整理来自于视频点击跳转

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值