多线程

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

多线程

main()是主线程

线程创建

三种创建方式

  • 继承Thread类
  • 实现Runnable接口
  • 实现Callable接口

继承Thread类

//线程创建方式一 :
/*
第一步:继承Thread类
第二步:重写run()方法
第三步:创建继承了Thread类的对象 , 调用start()方法启动。
 */
public class TestThread1 extends Thread{

    //自定义run方法的线程
    @Override
    public void run() {
        //线程执行体
        for (int i = 0; i < 200; i++) {
            System.out.println("有人在写笔记-->"+i);
        }
    }


    //主线程
    public static void main(String[] args) {

        //创建线程对象
        TestThread1 testThread1 = new TestThread1();
        //start() 方法用来 启动线程;
        testThread1.start();

        for (int i = 0; i < 3000; i++) {
            System.out.println("有人在在睡觉sleep-->"+i);
        }

    }

}

主线程走star 子线程走run

public class TestThread1 extends Thread{//(第二部)实现一个线程类 通过继承Thread
    private String url;
    private String name;//用构造器放入图片地址和名字,同时定义了调用线程类的初始属性,这是构造器的功能,没有具体的值,类似类的形参
    public TestThread1(String url,String name){
        this.url = url;
        this.name = name;
        
    }

//run方法为线程的执行体,写线程类时首先重写run方法 是每一个线程都要做的事情,每一个线程抽象出来的具体做法写在线程类中,然后通过主方法启动线程,最后线程会同时启动
    @Override
    public void run() {
        WebDownLoade webDownLoade = new WebDownLoade();
        webDownLoade.downloder(url,name);//下载图片通过类名调用方法
        System.out.println("下载了文件名"+name);//输出一下名字
    }
    
    
    //第三步在主方法上输入地址及启动线程
    public static void main(String[] args){
         //创建线程对象,也就是放入实参的过程,需要new线程类对象实现
        TestThread1 t1 =new TestThread1("https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2771978851,2906984932&fm=26&gp=0.jpg","2.jpg");
        TestThread1 t2=new TestThread1("https://tse4-mm.cn.bing.net/th/id/OIP.ZTmNathhKflijArYDaQEDAHaEo?w=234&h=180&c=7&o=5&dpr=1.25&pid=1.7","3.jpg");
        TestThread1 t3 =new TestThread1("https://tse3-mm.cn.bing.net/th/id/OIP.H986GDFYxiuR5pDYvu5uvgHaLH?w=115&h=180&c=7&o=5&dpr=1.25&pid=1.7","4.jpg");
        TestThread1 t4 =new TestThread1("https://tse1-mm.cn.bing.net/th/id/OIP.KYaksEiOCQPXilet3OQ1HQHaEo?w=266&h=180&c=7&o=5&dpr=1.25&pid=1.7","5.jpg");
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}
//下载器(第一步)
class WebDownLoade{
//    下载方法 (通过把图片转文件下载)
    public void downloder(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IO异常,downloder方法出现问题");
        }
    }
}

实现runnable接口

public class TextThread2 implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 200; i++) {
            System.out.println("kandaima");
        }

    }

    public static void main(String[] args) {
        //runnable接口实现类对象
        TextThread2 thread2 = new TextThread2();
//        创建线程对象,通过线程对象开启线程, 代理
//        Thread thread = new Thread(thread2);
//        thread.start();
//        等于下面一行
        new Thread(thread2).start();
        for (int i = 0; i < 200; i++) {
            System.out.println("多线程");
        }

    }
}

改造thread类为Runnable接口

public class TestThread1 implements Runnable
new  Thread(t1).start();
new  Thread(t2).start();
new  Thread(t3).start();
new  Thread(t4).start();

并发问题

//多个线程操作同一个对象
public class TestTheard3 implements Runnable{

//    票数
    private int ticketNums = 10;

    @Override
    public void run() {
    while (true){
        if (ticketNums<=0){
            break;
        }
        //设置延时200ms
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"拿到了第"+ticketNums--+"票");

    }
    }

    public static void main(String[] args) {
        TestTheard3 ticked = new TestTheard3();
        new Thread(ticked,"小明").start();
        new Thread(ticked,"小黑").start();
        new Thread(ticked,"小白").start();
        new Thread(ticked,"小王").start();

    }
}


小王拿到了第10票
小白拿到了第9票
小黑拿到了第10票
小明拿到了第10票
小明拿到了第6票
小白拿到了第7票
小黑拿到了第8票
小王拿到了第5票
小王拿到了第4票
小白拿到了第3票
小黑拿到了第2票
小明拿到了第1票

Process finished with exit code 0

当多个线程操作同一个对象时,拿到同一个数据,线程一起工作。

语法区别,继承Thread类要启动线程,需要new 这个对象然后。start

实现Runnable接口启动线程,需要newThread,然后丢入new 的Runnable类的对象

代理模式

真实对象和代理对象都要实现同一个接口

代理模式更像一个工具类,代理对像总结出一个抽象的流程,传入的都是形参,真实对象需要有一个具体的角色

代理对像可以做真实对象做不到的事情

真实对象可以专注自己的事情

五大状态

new -》就绪 ——》运行——》阻塞(可能)——》死亡

new:新生,创建线程对象

就绪:调用start方法时进入就绪状态

运行:不是立即运行

阻塞:调用Sleep wait等进入

死亡;线程中断

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4iHAyqMP-1619236330036)(…/…/AppData/Roaming/Typora/typora-user-images/image-20210423102834563.png)]

线程停止

推荐在main方法中加入控制语句来控制停止

线程休眠sleep

指定阻塞毫秒数

时间到达进入就绪状态

//延时模拟放大问题的发生性

10秒倒计时

public class TestSleep {
    public static void main(String[] args) throws InterruptedException {
        TenDown(10);

    }


    static void TenDown(int a) throws InterruptedException {
        int num = a;
        while (true){
            Thread.sleep(1000);
            System.out.println(num--);
            if (num <= 0){
                System.out.println("计时结束");
                break;
            }
        }
    }
}

yield 线程礼让

让cpu重新调度,不一定成功,运行状态转换为就绪状态

public class yield implements  Runnable{

    public static void main(String[] args) {
        yield yield = new yield();
        new Thread(yield,"a").start();
        new Thread(yield,"b").start();

    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"线程开始执行");
        Thread.yield();
        System.out.println(Thread.currentThread().getName()+"线程结束执行");
    }
}
b线程开始执行
a线程开始执行
a线程结束执行
b线程结束执行

a线程开始执行
a线程结束执行
b线程开始执行
b线程结束执行

强制执行join

例子。在主线程到20前,随即运行,但是主线程i达到20,调用join方法,会将子线程那个thread执行结束再运行主线程,会造成线程阻塞。

public class joinTest implements Runnable{

    public static void main(String[] args) throws InterruptedException {
        joinTest  join  = new joinTest();
        Thread thread = new Thread(join);
        thread.start();


        for (int i = 0; i < 100; i++) {
            if (i == 20){
                thread.join();
            }
            System.out.println("主线程"+i);
        }
 }
    
     @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("子线程插队"+i);
        }
    }
}

线程状态观察

lambda创建线程

Thread thread = new Thread(()->{
    for (int i = 0; i <= 5; i++) {
        try {
            Thread.sleep(1000);

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    System.out.println("");
});

线程观测,线程只能有一个start启动

Thread.State state = thread.getState();//创建这个线程监听
    System.out.println(thread.getState());//输出这个状态,此时为new
    thread.start();//启动线程进入Runnable
    state = thread.getState();
    while (state != Thread.State.TERMINATED){
        System.out.println(state);
        state = thread.getState();
        Thread.sleep(1000);
    }
}

线程优先级

优先级高的可能会先跑,但是不一定,具体看cpu调度

System.out.println(Thread.currentThread().getName()+"主线程优先级"+Thread.currentThread().getPriority());
mypro mypro = new mypro();
Thread t1 = new Thread(mypro);
Thread t2 = new Thread(mypro);
Thread t3 = new Thread(mypro);
Thread t4 = new Thread(mypro);
Thread t5 = new Thread(mypro);

t1.setPriority(1);
t1.start();
t2.setPriority(2);
t2.start();

守护线程

守护程序正常运行

设置方法 线程对象名字.setDemon(ture); 默认为false 为用户进程,ture为守护线程

liuyue liuyue = new liuyue();
snake snake = new snake();
Thread thread = new Thread(snake);
thread.setDaemon(true);
thread.start();
new Thread(liuyue).start();

线程同步

并发 多个线程同时操作一个对象

比如抢票

synchronized 同步方法

synchronized默认锁的是他本身,如果是方法里面的内容逻辑细节导致的,应该用synchronized块来锁内容,是一个监视器,难的是找到需要琐谁

方法头

synchronized(obj(要锁的对象)){

语句块

}

锁机制

修改内容才需要锁,锁会让效率变低

死锁

一个同步块有 两个以上对象的锁,可能会发生死锁,多个线程同时互相有对方需要的资源,形成僵持

Lock锁

final ReentrantLock lock = new ReentrantLock();

try {
   lock.lock
}catch{}
finally{
lock.unlock
}
class  ticket implements Runnable{
    int Ticket = 10;
    final ReentrantLock lock  =  new ReentrantLock();//定义Lock锁
    @Override
    public void run() {
        while (true){

            try {
                lock.lock();//加锁
                if (Ticket > 0){
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(  Ticket--);
            }else {
                break;
            }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();//关锁
            }
        }

    }
}

线程协作 生产,消费

这是一个线程同步问题
生产者和消费者共享同一个资源,并且生产者和消费者之
间相互依赖,互为条件.
对子生产,没有生产产品之前,要通知消费者等待﹒而生产了产品之后,又需要马上通知消费者消费
对于消费者﹐在消费之后,要通知生产者已经结束消费﹐需要生产新的产品以供消费.
在生产者消费者问题中﹐仅有synchronized是不够的
synchronized可阻止并发更新同一个共享资源,实现了同步

synchronized不能用来实现不同线程之间的消息传递(通信)

wait()
wait(long timeout)
notify()
notifyAll()

wait()
表示线程一直等待﹐直到其他线程通知,与sleep不同,会释放锁
wait(long timeout)
指定等待的毫秒数
notify()
唤醒一个处于等待状态的线程
notifyAll()
唤醒同一个对象上所有调用wait()方法的线程﹐优先级别高的线程优先调度

三种解决方法

  1. 管程法 建立缓冲区类

缓冲区就像一个容器,设置当生产者生产出来东西,容量加一,然后设置条件,

如果满了 通知消费者 如果没满 消费者等待

如果没满,放入生产者的产品

由消费者执行线程。

  1. 信号灯发 判断标志位 flag

线程池

能提高系统性能

提高响应速度,降低消耗,便于管理

创建使用 ExecutorService和Executors方法类

corePoolSize:核心池的大小

maximumPoolSize:最大线程数
keepAliveTime:线程没有任务时最多保持多长时间后会终止

ExecutorService创建线程池

void execute(Runnable command)∶执行任务/命令,没有返回值,一般用来执行Runnable
Future submit(Callable task):执行任务,有返回值,一般又来执行Callable
void shutdown():关闭连接池
Executors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池

1lamda表达式

解决:匿名内部类过多的问题,使代码更加简洁

接口必须为函数式接口,一个接口只包含一个抽象方法,为函数式接口

由匿名内部类推到得出

构造器

接口 命名 = (参数)-> { 语句块};

ILike like4 = (接口定义的参数,没有为空) -> {
    System.out.println();
};
like4.接口的方法

简化

多行代码

1。去掉参数类型 多个参数必须加括号

Love love = (a) ->{
        System.out.println("123"+a);
    };

love.love(2);

单个参数可以去掉括号

Love love2 = a ->{
    System.out.println("123"+a);
};
love.love(2);

单个参数,只需要一句代码,可去掉大括号

Love love3 = a -> System.out.println("123"+a);
love.love(2);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值