栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

多线程详解

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

多线程详解

多线程

并发和并行的区别:

并发:单核CPU同时处理多件事情,

并行:同一时间,多核CPU处理多个事情。

1. 多线程的四种创建方式
    继承Thread类实现Runable接口实现Callable接口线程池创建

线程池的好处(线程复用,控制最大并发数,管理线程)

    降低资源的消耗降低响应速度方便管理
Runnable 和Callable 的区别
runnable run方法无返回值,callable call方法有返回值
runnable run方法只能抛出运行时异常,callable call方法能够捕获异常信息
// 实现方式一: 继承Thread类
public class MythreadDemo{

    public static void main(String[] args) {
        new Mythread().start();
    }
}

class Mythread extends Thread{
    @Override
    public void run() {
        System.out.println("mythread runu");
    }
}
//实现方式二:继承Runnable接口
public class MyRunnableDemo {
    public static void main(String[] args) {
        new Thread(new MyRunnable()).start();
    }
}

class MyRunnable implements Runnable{
    @Override
    public void run() {
        System.out.println("myruunnable run");
    }
}
//实现方式三:实现Callable接口

public class MyCallableDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask future = new FutureTask<>(new MyCallable());
        new Thread(future,"A").start();
        new Thread(future,"B").start();

        System.out.println(future.get());
    }
}

class MyCallable implements Callable{
    @Override
    public String call() throws Exception {
        System.out.println("MyCallableDemo run"+Thread.currentThread().getName());
        
        return "wdddong";
    }
}
1.1 线程池的五种创建方式
    newFixThreadPool //创建单个线程newCachedThreadPool //创建一个可伸缩的线程池newScheduledThreadPool //newSingleThreadExecutor //创建一个固定的线程池大小newThreadPoolExecuted(自定义线程池)
1.1.1 使用 Executors 创建线程的弊端

为什么阿里巴巴开发手册中强制不建议使用Executors创建线程池,使用Executors创建的线程池有什么弊端?

public class Demo {
    public static void main(String[] args) {
        Executors.newCachedThreadPool();
        Executors.newFixedThreadPool(1);
        Executors.newSingleThreadExecutor();
        Executors.newScheduledThreadPool(1);
    }
}
	//1. newCachedThreadPool
	public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue());
    }
	//2. newScheduledThreadPool
    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }
    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }
	//3. newFixedThreadPool
    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new linkedBlockingQueue());
    }
    public linkedBlockingQueue() {
        this(Integer.MAX_VALUE);
    }
    //4. newSingleThreadExecutor
    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new linkedBlockingQueue()));
    }
    newCachedThreadPool,newScheduledThreadPool 允许的线程(非核心线程)数量为 Integer.MAX_VALUE,会创建大量的线程,可能会导致OOMnewFixedThreadPool,newSingleThreadExecutor 允许创建的请求队列长度为 Integer.MAX_VALUE,会堆积大量的请求,可能会导致OOM
1.1.2 自定义线程池中的参数说明
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue workQueue,
                              RejectedExecutionHandler handler);

#参数说明
corePoolSize:核心线程数量
maximumPoolSize:最大线程数
keepAliveTime:存活时间,(除了核心线程之外,其他的线程超时了没有人调用就会释放的时间)
unit:存活单位
workQueue:阻塞队列
handler:拒绝策略
## 拒绝策略:默认是直接抛出异常
    1. AbortPolicy:抛出异常
    2. CallRunsPolicy: 只用调用者所在的线程处理任务
    3. DiscurdOldestPlicy:队列满了,丢弃队列中最近的一个任务,来执行最新的任务(尝试和最早的任务做一个竞争)
    4. DisCardPolicy:队列满了,不处理直接丢弃

1.2 自定义线程池中最大的线程数量应该如何设置
    IO密集型: 判断你程序中十分耗IO 的数量(假设你的程序中有15 个大型任务,IO十分占用资源 。设置最大线程数 > 15 就好)CPU 密集型: 查看自己的CPU 是几核的。可以保持CPU效率最高 (程序中获取线程数: Runtime.getRuntime().availableProcessores() )
1.3 线程池中核心线程,最大线程,队列的执行顺序
    public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        
         
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command);
    }
1.3.1 任务添加顺序

1.3.2 任务执行顺序

先执行线程(核心+最大线程)中的任务,最后再执行任务队列中的任务

2. 线程中的状态(6种状态) 2.1 线程的六种状态

新生 (NEW )运行(RUNNABLE)阻塞(BLOCKED)超时等待(TIMED_WAITING)等待(WAITTING)销毁(TERMINATED ) 2.2 线程状态分析

3. 线程中的常用方法
方法备注
setPriority()设置线程的优先级。0==》10 ,优先级越大,被执行的可能性越高
sleep()让当前线程休眠,每个线程都有一把锁,sleep不会释放锁
join()等待该线程停止
yiled()释放CPU时间片,让线程进入就绪状态,重新争夺CPU时间片
interupt()中断线程
deamon()守护线程:(虚拟机是不用等待守护线程结束的)
3.1 Sleep 和 wait 方法的区别?
    wait 是Object 类的方法, sleep 是线程类 Thread 的静态方法wait 不需要捕获异常 ,sleep 需要捕获异常wait 会释放锁,sleep不会释放锁。wait方法需要notify,notifyAll唤醒notify 方法是随机唤醒一个线程。wait 的调用位置只能在同步代码块中,sleep 可以在任何地方进行调用
3.2 线程池中submit(),execute() 方法有什么区别?

接收的参数不一样sumbit() 有返回值,而execute 没有submit方便exception处理 4. 多线程中的锁 4.1 Synchronized锁

Synchronize 锁对象的分析:

静态方法: 静态方法 synchronize 锁的是 Class实例方法: synchronize 锁的是 方法的调用对象代码块:可以任意的去指定是锁Class模板还是具体对象 4.2 Lock锁

private Lock lock = new ReentrantLock();
lock.lock();
lock.unlock();
4.3 Synchronized 和 Lock 的区别
    Synchronized 是内置的 java关键字,Lock是一个Java类Synchronized 无法判断获取锁的状态,Lock可以判断是否获取到了锁Synchronized 可以自动释放锁,Lock需要手动释放(不释放会造成死锁)
5. 生产者消费者案例分析 5.1 Synchronized 版生产者消费者问题
奶箱类
public class Box {
    //定义一个成员变量,表示第x瓶奶
    private int milk;

    //定义一个成员变量,表示奶箱的形态
    private boolean state = false;

    //提供存储牛奶和获取牛奶的操作
    public synchronized void put(int milk) {
        //如果有牛奶,等待消费
        if(state){
            try{
                wait();//等待
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        //如果没有牛奶,就生产牛奶
        this.milk = milk;
        System.out.println("送奶工将第"+this.milk+"瓶奶放入奶箱");

        //生产完毕之后,修改奶箱状态
        state = true;

        //唤醒其他等待的线程
        notifyAll();
    }

    public synchronized void get(){
        //如果没有牛奶,等待生产
        if(!state){
            try{
                wait();
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        //如果有牛奶,就消费牛奶
        System.out.println("用户拿到第"+this.milk+"瓶奶");

        //消费完牛奶后,修改奶箱状态
        state = false;

        //唤醒其他等待的线程
        notifyAll();
    }
}

//生产者

public class Producer implements Runnable {
    private Box b;


    public Producer(Box b) {
        this.b = b;
    }

    @Override
    public void run() {
        for(int i=1;i<=5;i++){
            b.put(i);//送奶人往奶箱放入奶
        }
    }
}

//消费者
public class Customer implements Runnable {
    private Box b;
    public Customer(Box b) {
        this.b = b;
    }

    @Override
    public void run() {
        while (true){
            b.get();//得到牛奶
        }
    }
}

public class BaS {
    public static void main(String[] args) {
        Box box = new Box();//奶箱类

        Producer p = new Producer(box);//生产者对象

        Customer c = new Customer(box);//消费者对象

        //创建2个线程对象,分别把生产者对象和消费者对象作为构造方法参数传递
        Thread t1 = new Thread(p);
        Thread t2 = new Thread(c);

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

    }
}

5.2 线程的虚假唤醒问题
package com.example.testmodule;



public class test {
    public static void main(String[] args) {
        Box box = new Box();


        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 50; i++) {
                try {
                    box.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A");
        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 50; i++) {
                try {
                    box.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "B");
        Thread thread3 = new Thread(() -> {
            for (int i = 0; i < 50; i++) {
                try {
                    box.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "C");
        Thread thread4 = new Thread(() -> {
            for (int i = 0; i < 50; i++) {
                try {
                    box.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "D");
        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
    }
}

class Box {
    public int num;

    public synchronized void increment() throws InterruptedException {
        if (num != 0) {
        // while (num != 0){
            this.wait();
        }
        System.out.println("put:" + num++ + " have:" + num);
        notifyAll();
    }

    public synchronized void decrement() throws InterruptedException {
        if (num == 0) {
        //while (num == 0){
            this.wait();
        }
        System.out.println("get:" + num-- + " have:" + num);
        notifyAll();
    }
}

# 模拟的结果
put:0 have:1
get:1 have:0
put:0 have:1
get:1 have:0
get:0 have:-1
get:-1 have:-2
get:-2 have:-3
get:-3 have:-4
get:-4 have:-5
get:-5 have:-6 .......
5.3 Lock 版生产者消费者问题
package com.wddongtt.wddong.manyThread;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Box {
    //定义一个成员变量,表示第x瓶奶
    private int milk;

    //定义一个成员变量,表示奶箱的形态
    private boolean state = false;
    
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    //提供存储牛奶和获取牛奶的操作
    public void put(int milk) {
        try {
            lock.lock();
            //如果有牛奶,等待消费
            while(state){
                try{
                    condition.await();//等待
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
            //如果没有牛奶,就生产牛奶
            this.milk = milk;
            System.out.println("送奶工将第"+this.milk+"瓶奶放入奶箱");

            //生产完毕之后,修改奶箱状态
            state = true;

            //唤醒其他等待的线程
            condition.signalAll();

        }catch (Exception e){
            e.printStackTrace();
        }finally {

            lock.unlock();
        }
    }

    public void get(){
        try {
            lock.lock();
            //如果没有牛奶,等待生产
            while(!state){
                try{
                    condition.await();
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
            //如果有牛奶,就消费牛奶
            System.out.println("用户拿到第"+this.milk+"瓶奶");

            //消费完牛奶后,修改奶箱状态
            state = false;

            //唤醒其他等待的线程
            condition.signalAll();

        }catch (Exception e){

        }finally {
            lock.unlock();
        }
    }
}

//生产者

class Producer implements Runnable {
    private Box b;


    public Producer(Box b) {
        this.b = b;
    }

    @Override
    public void run() {
        for(int i=1;i<=5;i++){
            b.put(i);//送奶人往奶箱放入奶
        }
    }
}

//消费者
class Customer implements Runnable {
    private Box b;
    public Customer(Box b) {
        this.b = b;
    }

    @Override
    public void run() {
        while (true){
            b.get();//得到牛奶
        }
    }
}

class BaS {
    public static void main(String[] args) {
        Box box = new Box();//奶箱类

        Producer p = new Producer(box);//生产者对象

        Customer c = new Customer(box);//消费者对象

        //创建2个线程对象,分别把生产者对象和消费者对象作为构造方法参数传递
        Thread t1 = new Thread(p);
        Thread t2 = new Thread(c);

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

    }
}


5.4 Lock 中 Condition 的精确唤醒

LOCK 对比 Synchronize 的优势在于 LOCK 能够精确唤醒。

LOCK 中的睡眠和唤醒

睡眠: await()唤醒: signal(),signalAll()

#精确的通知和唤醒线程
package com.sjmp.demo02PC;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;



public class ConditionDemo {
    public static void main(String[] args) {
        Data3 data3 = new Data3();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                data3.printA();
            }
        },"A").start();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                data3.printB();
            }
        },"B").start();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                data3.printC();
            }
        },"C").start();
    }
}

class Data3{
    private Lock lock = new ReentrantLock();
    private Condition condition1 = lock.newCondition();
    private Condition condition2 = lock.newCondition();
    private Condition condition3 = lock.newCondition();
    private int num = 1; // 1A 2B 3C

    public void printA(){
        lock.lock();
        try {
            while (num != 1){
                condition1.await();
            }
            System.out.println(Thread.currentThread().getName()+" Im A ");
            num = 2;
            //唤醒2
            condition2.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void printB(){
        lock.lock();
        try {
            while (num != 2){
                condition2.await();
            }
            System.out.println(Thread.currentThread().getName()+" Im B ");
            num = 3;
            //唤醒3
            condition3.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void printC(){
        lock.lock();
        try {
            while (num != 3){
                condition3.await();
            }
            System.out.println(Thread.currentThread().getName()+" Im C ");
            num = 1;
            // 唤醒1
            condition1.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/732691.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号