多线程相关

  • 概念:在操作系统中,所有的运行中的任务通常对应一个进程,当一个程序进入到内存运行时,即变成一个进程,进程是运行过程中的程序,并具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位。
  1. 进程:是正在运行的程序,是系统进行组员分配和调用的独立单位,每个进程都有它自己的内存空间和系统资源。
    • 进程有三个特性,独立性,动态性,并发性。
  2. 线程:是进程中的单个顺序控制流,是一条执行路径
    1. 单线程:一个进程如果有一条执行路径,则称为单线程程序
    2. 多线程:一个进程如果有多条执行路径,则称为多线程程序
  • 多线程是为了同步完成多项任务,不是为了提高运行效率,而是为了提高资源使用效率来提高系统的效率。线程是在同一时间需要完成多项任务的时候实现的。最简单的比喻多线程就像火车的每一节车厢,而进程则是火车。车厢离开火车是无法跑动的,同理火车也不可能只有一节车厢。多线程的出现就是为了提高效率。同时它的出现也带来了一些问题。(来自百度百科)
实现方式
  1. 继承Thread类

    1. 写一个类继承Thread类,重写run()方法,线程要实现的功能,任务

    2. 在main方法中创建类的对象,低啊用红start()方法开启线程执行任务

    public class ThreadDemo extends Thread {
       @Override
       public void run() {
           for (int i = 0; i < 100; i++) {
               System.out.println(Thread.currentThread().getName()+":"+i);
           }
       }
    }
    
    public class Test01 {
       public static void main(String[] args) {
          ThreadDemo demo = new ThreadDemo();
          Thread thread = new Thread(demo);
          /*demo.run();*/
          thread.start();
       }
    }
    
  2. 实现Runnable接口

    1. 定义一个类实现Runnable接口,重写接口中的run()方法
    2. 在main方法忠创建Thread类对象,把接口实现类对象放在参数中,调用Thread对象的start()方法
    public class ThreadDemo implements Runnable{
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                System.out.println(Thread.currentThread().getName()+":"+i);
            }
        }
    }
    
    public class Test01 {
        public static void main(String[] args) {
           ThreadDemo demo = new ThreadDemo();
           Thread thread = new Thread(demo);
           /*demo.run();*/
           thread.start();
        }
    }
    

** 如果调用run()方法,是不会开启线程的。

生命周期
  1. 新建:线程的对象刚刚创建
  2. 就绪:线程调用了start()方法,在这个状态,线程等待CPU执行
  3. 执行:线程抢到了CPU的执行权,可以执行了
  4. 阻塞:线程调用了sleep()方法或wait(1000)方法,就会进入阻塞状态,这个时候,线程没有执行权,阻塞结束了,会进入就绪状态
  5. 无限阻塞:线程调用了wait()方法,进入无限阻塞状态,需要别的线程叫醒它,它才能够进入就绪状态
  6. 死亡:执行任务结束就进入死亡
解决线程死锁的两种方式

解决线程安全问题的两种方式

    1.同步代码块
      synchronized(任意对象){
    }
    2.同步方法:
        成员同步方法:它的同步锁是this
        public synchronized void sell(){
        }
        静态同步方法:它的同步锁是类名.class
        public static synchronized void sell(){
        }
    3.Lock锁
        Lock lock = new ReentrantLock();
        lock.lock();
        lock.unlock();
        try{
            lock.lock();
            ...
        }finally{
            lock.unlock();
        }

线程池

​ 线程池就是首先创建一些线程,它们的集合称为线程池。使用线程池可以很好地提高性能,线程池在系统启动时即创建大量空闲的线程,程序将一个任务传给线程池,线程池就会启动一条线程来执行这个任务,执行结束以后,该线程并不会死亡,而是再次返回线程池中成为空闲状态,等待执行下一个任务。

线程池家族

1.线程池的最上层接口是Executor,这个接口定义了一个核心方法execute(Runnabel command),这个方法最后被ThreadPoolExecutor类实现,这个方法是用来传入任务的。而且ThreadPoolExecutor是线程池的核心类,此类的构造方法如下:

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue);
 
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
            BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory);
 
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler);
 
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler);

corePoolSize:核心线程池的大小,如果核心线程池有空闲位置,这是新的任务就会被核心线程池新建一个线程执行,执行完毕后不会销毁线程,线程会进入缓存队列等待再次被运行。

maximunPoolSize:线程池能创建最大的线程数量。如果核心线程池和缓存队列都已经满了,新的任务进来就会创建新的线程来执行。但是数量不能超过maximunPoolSize,否侧会采取拒绝接受任务策略,我们下面会具体分析。

keepAliveTime:非核心线程能够空闲的最长时间,超过时间,线程终止。这个参数默认只有在线程数量超过核心线程池大小时才会起作用。只要线程数量不超过核心线程大小,就不会起作用。

unit:时间单位,和keepAliveTime配合使用。

workQueue:缓存队列,用来存放等待被执行的任务。

threadFactory:线程工厂,用来创建线程,一般有三种选择策略。 (ArrayBlockingQueue;LinkedBlockingQueue;SynchronousQueue;)

​ handler:拒绝处理策略,线程数量大于最大线程数就会采用拒绝处理策略,四种策略为 :

  • ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
  • ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
  • ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
  • ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务

Executor接口有一个子接口ExecutorService,ExecutorService的实现类为AbstracExecutorService,而ThreadPoolExcutor正是AbstrcExecutorService的子类。

ThreadPoolExecutor还有两个常用的方法shutdown和submit,两者都用来关闭线程池,但是后者有一个结果返回。

import java.util.concurrent.*;

public class BoxDemo {
    public static void main(String[] args) {
        Box b = new Box();
        Producer p = new Producer(b);
        Customer c = new Customer(b);
        //创建一个同步队列,容量为1(线程工厂)
        BlockingQueue<Runnable> bq = new ArrayBlockingQueue<>(1);
        //创建一个线程池,核心线程的大小为2,能创建的最大线程数为5。
        // new ThreadPoolExecutor.AbortPolicy()当超过最大线程任务时,
        // 丢弃任务并抛出RejectedExecutionException异常。
        ThreadPoolExecutor pool = new ThreadPoolExecutor(2,5,60L,
                TimeUnit.MILLISECONDS,bq,new ThreadPoolExecutor.AbortPolicy());
        pool.execute(p);
        pool.execute(c);
        pool.shutdown();
    }
}

####ForkJoinPool

1.说明:提供ForkJoinPool支持将一个大任务拆分成多个小任务,再把小任务合并成总的计算结果,是一种特殊的线程池。

发布-订阅框架

1.该框架是基于异步响应流,非常方便地处理异步线程之间的流数据交换,该框架不需要使用数据中心来缓冲数据,同时具有非常高效的性能。

2.该框架使用Flow类的4个静态内部接口作为核心API:

方法名说明
Flow.Processor<T,R>作为订阅者和发布者的组件。
Flow.Publisher订阅者接收的项目(和相关控制消息)的生产者。
Flow.Subscriber消息的接收者。
Flow.Subscription代表发布者和订阅者之间的链接纽带,订阅者可以使用request()方法来获取数据项,也可以使用cancel()方法来取消订阅。

​ 为了处理一些通用发布者的场景,Flow.Publisher提供了一个SubmissionPublisher实现类,它可向当前订阅者异步提交非空的数据项,直到它被关闭,每个订阅者都能以相同的顺序接收新提交的数据项。

package com.thread;

import java.util.List;
import java.util.concurrent.Flow;
import java.util.concurrent.SubmissionPublisher;

public class PubSubTest {
    public static void main(String[] args) {
    	//创建一个发布者
        SubmissionPublisher<String> publisher = new SubmissionPublisher<>();
        //创建订阅者
        MySubscriber<String> subscriber= new MySubscriber<>();
        //注册订阅者
        publisher.subscribe(subscriber);
        System.out.println("开始发布数据........");
        List.of("java","python","Android","IOS","Lua","Redis").forEach(m ->{
            publisher.submit(m);
            try{
                Thread.sleep(500);
            }catch (Exception ex){}
        });
        publisher.close();
        synchronized ("error")
        {
            try{
                "error".wait();
            }
            catch (Exception ex){}
        }
    }

}

class MySubscriber<T> implements Flow.Subscriber<T> {
    private Flow.Subscription subscription;
    @Override
    //订阅时触发该方法。
    public void onSubscribe(Flow.Subscription subscription) {
        this.subscription = subscription;
        subscription.request(1);
    }

    @Override
    //接收到数据时触发该方法。
    public void onNext(T item) {
        System.out.println("接收到数据"+item);
        subscription.request(1);
    }

    @Override
    //订阅出错调用该方法
    public void onError(Throwable throwable) {
        throwable.printStackTrace();
        synchronized ("error")
        {
            "error".notifyAll();
        }
    }

    @Override
    //订阅结束时触发该方法
    public void onComplete() {
        System.out.println("订阅结束");
        synchronized ("error")
        {
            "error".notifyAll();
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值