线程与线程安全,生产消费者模型

线程与进程

2390. 从字符串中移除星号

给你一个包含若干星号 * 的字符串 s

在一步操作中,你可以:

  • 选中 s 中的一个星号。
  • 移除星号 左侧 最近的那个 非星号 字符,并移除该星号自身。

返回移除 所有 星号之后的字符串**。**

注意:

  • 生成的输入保证总是可以执行题面中描述的操作。
  • 可以证明结果字符串是唯一的。

示例 1:

输入:s = "leet**cod*e"
输出:"lecoe"
解释:从左到右执行移除操作:
- 距离第 1 个星号最近的字符是 "leet**cod*e" 中的 't' ,s 变为 "lee*cod*e"- 距离第 2 个星号最近的字符是 "lee*cod*e" 中的 'e' ,s 变为 "lecod*e"- 距离第 3 个星号最近的字符是 "lecod*e" 中的 'd' ,s 变为 "lecoe" 。
不存在其他星号,返回 "lecoe"

StringBuilder内置加,删。

  • 复习

在这里插入图片描述

  • 方案一:先放进去在扫描
  • 在这里插入图片描述

在这里插入图片描述

  • 方案二:一个个放,遇到*删除and弹出栈顶。
  • 在这里插入图片描述
  • 方案三:放到Stringbuilder
  • 在这里插入图片描述
  • 在这里插入图片描述

引入

在这里插入图片描述

  • cpu主要用于寻址。
  • 摩尔定律

是由英特尔(Intel)创始人之一戈登·摩尔(Gordon Moore)提出来的。其内容为:当价格不变时,集成电路上可容纳的元器件的数目,约每隔18-24个月便会增加一倍,性能也将提升一倍。换言之,每一美元所能买到的电脑性能,将每隔18-24个月翻一倍以上。这一定律揭示了信息技术进步的速度。 尽管这种趋势已经持续了超过半个世纪,摩尔定律仍应该被认为是观测或推测,而不是一个物理或自然法。预计定律将持续到至少2015年或2020年。然而,2010年国际半导体技术发展路线图的更新增长已经放缓在2013年年底,之后的时间里晶体管数量密度预计只会每三年翻一番。

在这里插入图片描述

进程是任务,线程是分配任务。

进程

在这里插入图片描述

并发与并行:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

多线程的缺点:管理不便。

在这里插入图片描述

new,start(创建,就绪),运行,堵塞,自然死亡。

package com.ffyc.thread;
   /**
     * 写10个1~10
     * 分任务!
     * @param args
     */

public class ThreadDemo02 extends Thread{
    public static void main(String[] args) {
        Thread t1 = new ThreadDemo02();

        Thread t2 = new ThreadDemo02();
        t2.start();//ready
        t1.start();//就绪,CPU有时间片才会运行,也不是一定运行。
    }

    @Override
    public void run() {
        for (int i = 1; i <=10 ; i++) {
            System.out.print(i+"\t");
        }
        System.out.println();
    }
}

在这里插入图片描述

线程生命周期

在这里插入图片描述

*核心

在这里插入图片描述
在这里插入图片描述

package com.ffyc.thread;

/**
 * Runnable接口实现(可以继承)
 * why:java单继承、多实现
 */
public class ThreadDemo03 implements Runnable{
    private String name;

    public ThreadDemo03(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(this.name+"-->"+i);
        }
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(new ThreadDemo03("A"));
        Thread t2 = new Thread(new ThreadDemo03("B"));

        t2.start();
        t1.start();
    }
}

在这里插入图片描述

Runnable

在这里插入图片描述

  • 对比函数式接口 VS 匿名内部类(接口在内部实现)

  • 在这里插入图片描述

  • 点灰色–>lambda表示式

  • 在这里插入图片描述

  • lambda表示式

  • List排顺序Camparator o1 - o2;逆序 o2- o1。

  • 在这里插入图片描述

  • 二维数组排序

  • 在这里插入图片描述

package com.ffyc.thread;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class SortDemo {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();//动态数组
        list.add(1);
        list.add(3);
        list.add(2);

        System.out.println(list);//无序:1 3 2 
        //自己写排序【empty】
        
        // OR jdk排
        list.sort(new A());//写一个A排序
        System.out.println("Sort:"+list);

        list.sort(new Comparator<Integer>() {//lambda
            @Override
            public int compare(Integer f, Integer l) {
                return f-l;
            }
        });
        System.out.println("first-last:"+list);

    }
}

package com.ffyc.thread;

public class ThreadDemo05 {
    public static void main(String[] args) {
        /**
         * Runnable匿名内部类
         */
        Thread t1 = new Thread(new Thread(() -> {
            for (int i=1;i<10;i++){
                System.out.println("A->"+i);
            }
        }));

        Thread t2 = new Thread(new Thread(() -> {
            for (int i=1;i<20;i++){
                System.out.println("B->"+i);
            }
        }));

        t1.start();
        t2.start();

    }
}

block():阻塞

三种解决方法:

  1. sleep()–>唤醒前要就绪
  2. yield
  3. join
  4. wait——高级别–》对all对象

在这里插入图片描述

可怕

在这里插入图片描述

List扩容时可能加入新的元素,不安全。

  • 在这里插入图片描述

守护线程和用户线程

守护最后一个用户线程结束才结束。

守护线程–> .setDaemon(true)
package com.ffyc.thread;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 守护线程
 */
public class ProtectThread {
    public static void main(String[] args) {
        Thread t1 = new Thread(()->{
            while (true){
                try {
                Date d = new Date();
                SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd hh:mm:ss");
                System.out.println(sdf.format(d));

                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        Thread t2 = new Thread(()->{
            for (int i = 0; i < 100; i++) {
                try {
                System.out.println("我是00"+i);

                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        t1.setDaemon(true);
        t1.start();
        t2.start();

    }

}

在这里插入图片描述
在这里插入图片描述

用户线程

复习:

  1. 线程
  2. 集合
  3. 面向对象

线程安全

回顾生命周期

在这里插入图片描述

三大特性

  1. 原子性(理论上)——线程任务不可再分。
  2. 可见性——线程之间的操作互相不可见。
  3. 有序性——程序运行顺序不能改变。

特性一:原子性 代码举例

int i = 1;
i++;

在这里插入图片描述
在这里插入图片描述

原子类–多线程时±/*安全。

AtomicXXX

package com.ffyc.Thread;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 特性一:原子性
 * i++/++i ===> 不安全---why:两步完成。
*/
public class ThreadDemo01 {
 //static int x = 1;
 static AtomicInteger a = new AtomicInteger(1);

 public static void main(String[] args) {
     Thread t1 = new Thread(new Runnable() {
         @Override
         public void run() {
             for (int i = 0; i < 100; i++) {
                 System.out.println(a.addAndGet(1));
                 try {
                     Thread.sleep(100);
                 } catch (InterruptedException e) {
                     throw new RuntimeException(e);
                 }
             }
         }
     });

     Thread t2 = new Thread(new Runnable() {
         @Override
         public void run() {
             try {
                 for (int i = 0; i < 100; i++) {
                     System.out.println(a.addAndGet(1));
                     Thread.sleep(100);
                 }
             } catch (InterruptedException e) {
                 throw new RuntimeException(e);
             }
         }
     });


     // 启动线程
     t1.start();
     t2.start();
 }
}

在这里插入图片描述

特性二:互盲

在这里插入图片描述
但不能保证有序。

Eg:

在这里插入图片描述
在这里插入图片描述

升级

在这里插入图片描述

package com.ffyc.thread;

public class ThreadDemo02 {

    static volatile boolean flag = false;

    public static void main(String[] args) {
        //线程A如果,flag为true,就运行打印语句 A: true
        Thread t1 = new Thread(() -> {
            while (true) {
                if (flag) {
                    System.out.println("A:" + flag);
                }
            }
        });

        //100ms之后将flag变为true
        Thread t2 = new Thread(() -> {
            try {
                Thread.sleep(100);
                flag = true;
                System.out.println("B:" + flag);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

        });
        t1.start();
        t2.start();

    }
}

特性三:不能改变固有顺序

在这里插入图片描述

“重点”解决线程安全方案——*锁🔒

原理

  1. 每一个对象只有一把锁,
  2. 每个线程抢锁,先拿到的线程就是锁的持有者。
  3. 持有锁的线程访问有synchronized标记的方法/代码块
  4. 离开synchronized,线程releas(释放)锁🔒

现实场景:买票程序

在这里插入图片描述

在这里插入图片描述

ticket
package com.ffyc.ticket;

public class Ticket {
    private Integer num;
    private String name;

    public Ticket(Integer num) {
        this.num = num;
    }

    public Ticket(Integer num, String name) {
        this.num = num;
        this.name = name;
    }

    /**
     * 取出剩余票数
     * @return
     */
    public Integer getNum() {
        return num;
    }

    /**
     * 卖票
     * @param name
     * //sy 同步 解决
     */

    public synchronized void sold(String name){

        System.out.println("站点"+name+"购买成功,余票"+ (--num)+"票");//why前减
    }
}

tivketThread
package com.ffyc.ticket;

public class TicketsThread extends Thread{
    private final String name;
    private final Ticket ticket;
    public TicketsThread(Ticket ticket,String name){
        this.ticket=ticket;
        this.name = name;
    }

    @Override
    public void run(){
       // synchronized (ticket.getNum()){//解决-1,-2票的打印问题,但是全是A买的。
            while (ticket.getNum()>2){//笨办法解决
                try {
                    sleep(100);
                    ticket.sold(name);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }


    //}

}

TicketTest
package com.ffyc.ticket;

public class TestTicket {
    public static void main(String[] args) {
        Ticket ticket = new Ticket(100);

        Thread a = new TicketsThread(ticket, "A");
        Thread b= new TicketsThread(ticket,"B");
        Thread c = new TicketsThread(ticket,"C");


        a.start();
        c.start();
        b.start();

    }
}

在这里插入图片描述

Ways:

  1. 方法体
  2. 方法里**{代码块},注意不能有基本数据类型,要用包装类型。**
改造Atomic
sy联系:StringBuffer,Vector。

在这里插入图片描述

Asy异步 ——》 前端里用

持有锁

在这里插入图片描述

死锁

sy(A){

​ sy(B){ }

}

在这里插入图片描述

Resource
package com.ffyc.lock;

public class Resource {
    private String name;

    public Resource(String name) {
        this.name= name;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "Resource{" +
                "name='" + name + '\'' +
                '}';
    }
}

DeadLockThread
package com.ffyc.lock;

public class DeadLockThread extends Thread{
    private Resource x;
    private Resource y;

    public  DeadLockThread(Resource x, Resource y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public void run() {
        synchronized (x){
            System.out.println(x.getName()+"锁定"+x.getName()+"成功...");
            try {
                sleep(200);
                System.out.println(x.getName()+"准备--->锁定"+y.getName()+">>>>");
                synchronized (y){
                    System.out.println(x.getName()+"锁定"+y.getName()+"成功...");
                }
                System.out.println("释放"+y.getName()+"成功...");
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        System.out.println("释放"+x.getName()+"成功...");
    }

}

Main
package com.ffyc.lock;

public class Main {
    public static void main(String[] args) {

        Resource lwh = new Resource("李文豪");
        Resource wzy = new Resource("隗子垚");
        Resource fzy = new Resource("冯正阳");

        Thread a = new DeadLockThread(lwh, fzy);
        Thread b = new DeadLockThread(fzy, wzy);
        Thread c = new DeadLockThread(wzy, lwh);

        a.start();
        b.start();
        c.start();
    }




}

在这里插入图片描述

leetcode191

        int num = 0;
      String s = Integer.toBinaryString(n);
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i)=='1') num++;
        }
        return num;

在这里插入图片描述

生产者消费者模型

在这里插入图片描述

hamburger类

在这里插入图片描述

HLS

在这里插入图片描述

在这里插入图片描述

用wait记得抛线程异常。

在这里插入图片描述
在这里插入图片描述

消费者consumer

在这里插入图片描述

Main

在这里插入图片描述

ProducerThread生产者线程

在这里插入图片描述

ConsumerThread

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值