多线程基础

进程和线程

  • 简单来说,一个程序就是一个进程,一个程序的多项任务就是多线程。进程就是一个程序执行时的实例,一个程序运行起来就会创建一个进程,然后系统给它分配资源,把它放到进程就绪队列里,等CPU调度到它,就给它分配调度时间,真正运行起来。一个线程就是一条执行路径。
  • 进程是系统分配资源的基本单位,线程是系统调度的基本单位;一个进程可以有多条线程,一条线程只能属于一个进程,但每个进程里面肯定会有一条主线程;一个进程里面的资源可以共享,每个线程都有各自的虚拟机栈,本地方法栈,程序计数器来保存自己的信息(上下文)。
  • 举个例子:曾经看到过别的大佬举的一个例子:把上课看成一个进程,老师就是一个CPU,正在听课的学生就是线程,这时有一个学生A突然听不懂了,就举手问老师,然后老师就给他去讲解,正在给A讲解的时候突然学生B又听不懂了,B又举手,然后老师又给B去讲解,给B讲完后又接着给A将。
  • 并发:并发是“假同时”,单核CPU在同一时间只能运行一个任务,CPU采用时间片轮转调度的方式来运行任务,也就是一会执行A任务,一会执行B任务·····,由于切换的速度非常快,给我们的感觉就好像几个任务同时在运行。
  • 并行:“真同时”,在多核CPU情况下,在同一时间每个CPU都在运行一个任务,真正做到了在同一时间同时有多个任务在运行。
  • 举个例子:现在有A,B,C·····10个任务,并发:我一会做会A任务,一会做会B任务,一会做会C任务,这几个任务来回切换着做。 并行:我又找来了我的一个小伙伴,我俩同时做任务,在同一时间真的有多个任务在运行。

创建线程的几种方式

  • 继承Thread类,重写run()方法,是将run()方法写在子类中,重写后就直接调用重写的run()方法,不再进行Runnable是否为空的判断,但是因为Java中是单继承,继承了Thread类,就不能再继承别的类了,所以会给继承方面带来缺陷。
public class Test {
    public static void main(String[] args) {
        MyThread thread=new MyThread();
        thread.start();
    }
}
class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
  • 实现Runnable接口,覆写run()方法,然后将Runnable丢给Thread,
    让Thread包裹一下。并没有重写父类方法,所以会首先判断Runnable是否为空,如果不为空,就去执行自己写的run()。
public class Test {
    public static void main(String[] args) {
        MyRunnable r=new MyRunnable();
        new Thread(r).start();
    }
}
class MyRunnable implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

  • 实现Callable接口,重写call()方法,实现带返回值的线程,还可以判断线程是否执行完毕和取消线程。
    Thread类将Callable封装成FutureTask,FutureTask又实现了RunnableFuture,RunnableFuture又继承了Runnable,所以本质上还是Runnable,RunnableFuture还继承了Future,Future里面有一些API可以判断线程是否执行完毕和取消线程等。
public class Test {
    public static void main(String[] args) {
        MyCallable c=new MyCallable();
        FutureTask task=new FutureTask(c);
        new Thread(task).start();
    }
}
class MyCallable implements Callable<Integer>{

    @Override
    public Integer call() throws Exception {
        int sum=0;
        for(int i=0;i<1000;i++){
            sum+=i;
        }
        return sum;
    }
}
  • 线程池

一般在创建后,线程池里面的线程池数量为0,在有任务来的时候才创建。

ThreadPoolExecutor poll=new ThreadPoolExecutor(3,
                5,
                2000,
                TimeUnit.MILLISECONDS,
                new LinkedBlockingDeque<>(5),
                new ThreadPoolExecutor.AbortPolicy()
        );

corePollSize:核心线程数量
maximumPollSize:最大线程数量,核心线程+非核心线程
keepAliveTime:非核心线程存活的最大空闲时间,也就是在没有任务的情况下非核心线程的最大存活时间
TimeUnit:存活的时间单位
workQueue:阻塞队列,用来存放任务
ThreadFactory:生产线程的工厂
handler:拒绝策略,有4种:
AbortPolicy:直接丢弃,并抛出异常
DiscardPolicy:直接丢弃,但并不会抛异常
DiscordOldestPolicy:丢弃队头任务,然后尝试执行
CallerRunsPolicy:调用线程去执行
执行过程:当有任务来的时候,线程池查看自己是否还有空闲的核心线程,如果有就让核心线程去执行任务,如果没有,就尝试把任务放到工作队列里,如果能放下就放,如果放不下就看现在的线程数是否已经到达最大线程数量,如果没有达到就创建线程去执行,如果已经到达了最大线程数就采取拒绝策略。

还可以通过Exector来创建:

        ExecutorService e1=Executors.newSingleThreadExecutor();
        ExecutorService e2=Executors.newCachedThreadPool();
        ExecutorService e3=Executors.newFixedThreadPool(4);

线程常用API

//Thread调用为静态方法,thread调用为实例方法

Runnable r=()-> System.out.println("线程");
        Thread thread=new Thread(r);

        //每个线程都有唯一的id
        long id=thread.getId();

        //获取线程名字
        String name=thread.getName();
        //设置线程名字
        thread.setName("线程2");
        //获取线程优先级,优先级高的有可能会被优先执行,但不是一定会被先执行
        int priority=thread.getPriority();
        //设置线程优先级
        thread.setPriority(2);
        //获取线程状态,线程转态是个枚举类
        Thread.State s=thread.getState();
        //NEW    RUNNABLE    BLOCKED    WAITING   TIMED_WAITING    TERMINATED
        for(Thread.State state:Thread.State.values()){
            System.out.println(state);
        }

        //判断线程是否是守护线程,jvm会在一个进程的所有非守护线程都结束后才会关闭
        //比如:GC就是守护线程
        boolean isD=thread.isDaemon();
        //判断线程是否存活
        boolean isA=thread.isAlive();
        //当前活跃的线程数量
        Thread.activeCount();
        //线程让步
        Thread.yield();
        //让线程睡眠
        Thread.sleep(3000);
        //等线程结束
        thread.join();


        /*
        * interrupt()并不会立刻停止一个线程,而是设置一个中断标志位,如果当前线程
        * 因为调用了wait(),join(),sleep()等而处于阻塞状态,调用interrupt()就会
        * 抛一个异常,清空所有标志位,如果当前线程并没有处于阻塞状态,就会设置一
        * 个中断标志位。
        * interrupted() 判断是否设置中断标志位,如果设置了会清空中断标志位
        * isInterrupted() 判断是否设置中断标志位,如果设置了并不会清空中断标志位
        * */
        thread.interrupt();
        Thread.interrupted();
        thread.isInterrupted();
        
        /*
        * wait(),notify(),notifyAll() 只能用于同步代码块或同步方法中,用于线程间的通信
        * 调用wait(),当前线程释放对象锁,并处于阻塞状态,阻塞在wait()代码行处,等其它线程
        * 调用当前对象的notify()或notifyAll()才能被唤醒,也不是立刻就被唤醒,需要等调用
        * notify()或notifyAll()的线程释放对象锁之后才能被唤醒
        * 
        * notify()随机唤醒一个线程,notifyAll()唤醒所有线程
        * 
        * */
        Object o=new Object();
        synchronized(o){
            o.wait();

            o.notify();

            o.notifyAll();
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值