多线程初始

线程简介

多任务

进程

  • 资源分配的最小单位

  • 运行起来的程序

  • 可以拥有多个线程

线程

  • 资源调度的最小单位

  • 独立执行的路径

  • 线程的运行由调度器调度,前后顺序是不能人为干预的

  • 对于同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制

  • 线程会带来额外的开销

  • 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致

注意:很多多线程都是模拟出来的额,真正的多线程是指有多个CPU,即多核。如果是模拟出来的多线程,即在一个cpu的情况下,在同一个时间点,cpu只能执行一个代码,因为切换的很快。所以就有同时执行的错觉。

线程实现(重点)

Thread类

  • 自定义线程类继承Thread类

  • 重写run()方法,编写线 程执行体

  • 创建线程对象,调用strat()方法

Runnable接口(建议)

  • 定义实现类,实现Runnable接口

  • 重写run()方法,编写线程执行体

  • 创建线程对象,构造函数中传入实现类对象,线程对象执行start()方法

静态代理

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

  • 代理对象需要代理真实对象,即真实对象传入代理对象

代理对象可以做很多真实对象做不了的事情

真实对象专注做自己该做的事情

Lambda表达式

函数式接口

  1. 普通实现类

  2. 静态内部类(需要的功能只需要一次)

  3. 局部内部类(需要的功能只需要一次)

  4. 匿名内部类(需要的功能只需要一次,需要的时候实现接口中的方法)

  5. lambda表达式简化

    函数式接口

函数式编程

避免匿名内部类定义过多

Callable接口(了解)

  • 实现Callable接口,该接口需要返回值类型,与call方法返回值相同

  • 重写call()方法,该方法有返回值

  • 创建目标对象

  • 创建执行服务

  • 提交执行

  • 获取结果

  • 关闭服务

  1. call()方法有返回值

  2. 可以抛出异常

线程不安全问题

线程状态

五大状态

创建,就绪,执行,阻塞,死亡

  • Thread方法

    1. sleep()

    2. join()

    3. isAlive()

    4. 等等

线程休眠 sleep

  • Thread.sleep()

线程礼让 yield

  • Thread.yield()

  • 将该线程有运行状态转为就绪状态,让cpu重新调度,礼让不一定成功

插队线程join

  • threadObj.join();

线程状态

  • Thread.State

  • threadObj.getState()

    1. NEW

    2. RUNNABLE

    3. BLOCKED

    4. WAITING

    5. TIME_WAI TING

    6. TERMINATED

线程的优先级

  • threadObj.setProprity()

  • threadObj.getProprity()

  • 范围1~10,值越大,优先级越高

守护线程 daemon

  • threadObj.setDaemon()

  • 线程分为用户线程和守护线程

    1. main线程

    2. gc线程

  • 正常的线程都是用户线程

  • 虚拟机不必等待守护线程执行完毕

线程同步(重点)

  • 多个线程操作同一个资源

  • 线程同步本质上是一种等待机制,多个需要同时访问此对象的线程进入对象的等待池形成队列

  • synchronized

队列+锁

三大不安全案例

  • 不安全买票

  • 不安全银行取票

  • 线程不安全的集合

同步方法及同步方法块

  • 方法上synchronized修饰符

    • 存在问题:锁太多,浪费资源

  • 同步块

    • synchronized(Obj) {}

  • 锁的对象就是变化的量。需要增删改的对象

    • 同步方法,this,指向这个类本身

    • 同步方法,谁变化锁谁。产生不安全的代码块,写在锁中

JUC安全类型的集合

  • CopyOnWriteArrayList线程安全

  • ArrayList线程不安全

死锁

  • 多个线程互相抱着对方需要的资源,并僵持住

    • 先抱着锁着自己的资源不放,并在锁住自己资源的内,还想锁住其他别人拥有的资源

  • 产生死锁的四个必要条件

    1. 互斥条件

    2. 请求与保持条件

    3. 不剥夺条件

    4. 循环等待

LOCK接口

  • 使用ReentrantLock类实现Lock

    • 显式加锁和释放锁

  • reentrantLockObj.lock();

  • reentrantLockObj.unlock();

Synchronized与Lock对比

  1. Lock显式,Synchronized隐式

  2. Lock只有代码块,Synchronized有方法锁和代码块锁

  3. Lock性能更好

优先使用顺序

Lock>同步代码块>同步方法

线程通信问题

生产者消费者模式

  • 在生产者和消费者问题中,仅有Synchronized是不够的

    1. synchronized可以阻止并发更新同一个共享资源,实现了同步

    2. synchronized不能用来实现 不同线程之间的通信

线程通信方法

wait()

wait(long time)

notify()

notifyAll()

解决方式一:管程法->缓冲区

public class TestPC {

    public static void main(String[] args) {

        Container container = new Container();

        new Producer(container).start();
        new Consumer(container).start();
    }

}

//生产者
class Producer extends Thread {
    Container container;

    public Producer(Container container) {
        this.container =  container;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            container.push(new Product(i));
            System.out.println("生产了第"+ i + "个产品");
        }
    }
}

//消费者
class Consumer extends Thread {

    Container container;

    public Consumer(Container container) {
        this.container =  container;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("消费了第"+ container.get().id + "个产品" );
        }
    }

}


//产品
class Product {
    int id;

    public Product(int id) {
        this.id = id;
    }
}

//缓冲区
class Container {

    //存放产品的容器大小
    Product[] products = new Product[10];
    int count = 0;

    //生产者放入产品
    public synchronized void push(Product product) {
        //如果容器满了,就需要等待消费者消费
        if(count == products.length){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        //如果没有满,就需要想容器中丢入产品
        products[count] =  product;
        count++;

        //通知消费者进行消费
        this.notifyAll();
    }


    //消费者消费产品
    public synchronized Product get() {
        //没产品了,等待生产者生产
        if(count == 0) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

        //如果有产品,则可以消费
        count--;
        Product product = products[count];

        //消费完,通知生产者生产
        this.notifyAll();

        return product;

    }
}

解决方式二:信号灯法

public class Test {
    public static void main(String[] args) {
        Food food = new Food();
        new Machine(food).start();
        new Diner(food).start();

    }

}


//生产者
class Machine extends Thread{
    Food food;

    public Machine(Food food) {
        this.food = food;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            this.food.make("鱼香肉丝");
        }
    }
}

//消费者
class Diner extends Thread {
    Food food;

    public Diner(Food food) {
        this.food = food;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            this.food.eat();
        }
    }
}

//食物
class Food {
    //机器制作食物时,(食客等待 true)
    //食客吃饭时,(机器等待 false)
    String foodName;
    boolean flag = true;

    //制作食物
    public synchronized void make(String foodName) {
        //假定flag为false时,机器等待
        if(!flag) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        System.out.println("机器制造了"+ foodName);

        //通知食客吃饭
        this.notifyAll();

        this.foodName = foodName;
        //更新标志
        this.flag = !flag;
    }

    //食客吃饭
    public synchronized void eat() {
        //假定flag为true时,食客等待
        if (flag) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        System.out.println("食客吃饭了" + foodName);

        //通知机器制作食物
        this.notifyAll();

        //更新标志
        this.flag = !flag;
    }
}

 

高级主题

线程池

  • 降低资源消耗

  • 提高响应速度

  • 便于线程管理

Executos工具类与ExecutorService

  • ThreadPoolExecutor类

    • Executors.newFixedThreadPool()

  • serviceObj.execute(threadObj)->执行Runnable

  • seviceObj.submit()->执行Callable

  • serviceObj.shutdown()

posted @ 2020-03-10 15:19  tikoblog  阅读(86)  评论(0)    收藏  举报