美文网首页
java多线程开发知识点汇总

java多线程开发知识点汇总

作者: 过期的薯条 | 来源:发表于2019-10-03 13:13 被阅读0次

    1.引言

    最近的工作大量运用了多线程的一些知识,才发现自己对这块知识有很多盲点,于是看看书,博客,写写,总结总结。

    2.正题

    1.线程的状态
    • 新建
      刚创建的时候的状态
    • 就绪
      等待获取cpu时间片
    • 阻塞
      阻塞状态的线程等待一个监视器锁以进入一个同步代码块/同步方法,或者该线程在调用wait()方法后重如该同步代码块/同步方法
    • 运行
    • 死亡
    1.java Thread.yield 方法

    yield方法 让出当前Thread的cpu,使当前线程变成就绪态,和其他线程一起竞争cpu资源。yield方法并没有终止当前线程的意思。

    2.线程池shutdown 和shutdownNow
    /**
         * Initiates an orderly shutdown in which previously submitted
         * tasks are executed, but no new tasks will be accepted.
         * Invocation has no additional effect if already shut down.
         *
         * <p>This method does not wait for previously submitted tasks to
         * complete execution.  Use {@link #awaitTermination awaitTermination}
         * to do that.
         *
         * @throws SecurityException {@inheritDoc}
         */
    

    shutdown方法本质调用线程池各个线程的interrupt()方法,调用这个方法之后,线程池将不再接受新的任务,调用这个方法之后,再submit一个任务就会报RejectedExecutionException异常

    /**
         * Attempts to stop all actively executing tasks, halts the
         * processing of waiting tasks, and returns a list of the tasks
         * that were awaiting execution. These tasks are drained (removed)
         * from the task queue upon return from this method.
         *
         * <p>This method does not wait for actively executing tasks to
         * terminate.  Use {@link #awaitTermination awaitTermination} to
         * do that.
         *
         * <p>There are no guarantees beyond best-effort attempts to stop
         * processing actively executing tasks.  This implementation
         * cancels tasks via {@link Thread#interrupt}, so any task that
         * fails to respond to interrupts may never terminate.
         *
         * @throws SecurityException {@inheritDoc}
         */
    

    shutdownNow和shutdown方法一样,唯一不同,shutdownNow会尽最大的可能去终止正在运行的任务,并且返回没有执行的Runnable

    3.Callable vs Runnable 接口

    Runnable 执行完毕没有返回值

    Callable执行完毕有返回值,通过Feture.get()获取返回值,此方法会使线程进入阻塞态

    public static void main(String[] args) {
            ThreadPoolExecutor m = (ThreadPoolExecutor) Executors.newCachedThreadPool();
    
            Future <String>f=m.submit(new Callable<String>() {
                @Override
                public String call() throws Exception {
                    Thread.sleep(8000);
                    return "wxy";
                }
            });
    
            System.out.println("开始阻塞");
            try {
                String s=f.get();
                System.out.println(s);
    
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
            System.out.println("结束");
        }
    
    4.线程优先级

    线程的等级在1-10之间,小于1 或者大于10 将报异常。优先级越高,获取cpu时间片越多,获取的几率也越大。通过setPriority方法设置

    5.后台线程

    后台线程,它是在后台运行的,它的任务是为其他线程提供服务,这种线程被称为“后台线程(Daemon Thread)”,又称为“守护线程”或“精灵线程”。JVM的垃圾回收线程就是典型的后台线程。当所有的用户线程(非守护线程)
    当所有的前台线程死亡了,后台线程也会自动消亡,注意的是前台线程死亡,不等于睡眠

    6.thread.join()

    在线程a中调用线程b的join()方法,会中断线程a的执行,等待线程b执行完毕才会在继续执行线程a。

    public static void main(String[] args) {
            Thread thread2=new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 10; i <20 ; i++) {
                        System.out.println(i);
                    }
                }
            });
    
            Thread thread1=new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i <10 ; i++) {
                        System.out.println(i);
                        if (i==5){
                            try {
                                thread2.start();
                                thread2.join();//放在start后面
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            });
            thread1.start();
        }
    
    输出:
    1 2 3 4 5 10 11 12  13  14  15  16  17  18 19  6  7  8  9
    
    7.java Lock对象

    synchronized 修饰的代码块或者方法,处于阻塞状态的时候,那么其他线程都无法访问这个方法,会一直阻塞下去。为了解决这种现象于是出现了Lock。Lock是一个接口,实现类是ReentrantLock ,ReentrantLock是一个可重入且独占式的锁,它具有与使用synchronized监视器锁相同的基本行为和语义,但与synchronized关键字相比,它更灵活、更强大,增加了轮询、超时、中断等高级功能。ReentrantLock,顾名思义,它是支持可重入锁的锁,是一种递归无阻塞的同步机制。除此之外,该锁还支持获取锁时的公平和非公平选择

    8.volatile 关键字

    volatile 关键字只能保证变量的可见性,在线程a中,被volatile修饰的变量a值改变,a将会通知其他所有线程从主存再次获取a的值,这样a改变了,那么其他线程在使用a的值的时候,是最新的值,而不是缓存下来的值

    9.ThreadLocal

    ThreadLocal 本地数据接口,以当前Thread 为key,value是我们set的值。相当于为每个thread保存一个副本。这样下次这个线程访问的就是自己保存的副本,保证了数据的唯一性,从根源上解决多线程问题

    10.Thread.interrupted vs thread.interrupt

    image.png

    这俩个方法都是用来获取前程是否中断的,唯一的不同点就是thread.interrupt不会重置状态。Thread.interrupted会重置状态(重置成false)。所有线程默认是非中断 的。重置的意思是:当一个线程设置成中断,第一次调用Thread.interrupted 将返回true,第二次调用将返回false。

    线程池关闭某一个线程java实现:

    public static void main(String[] args) {
            ThreadPoolExecutor mThreadPoolExecutor = (ThreadPoolExecutor) Executors.newCachedThreadPool();
            long t=System.currentTimeMillis();
            Future mFuture = mThreadPoolExecutor.submit(new Runnable() {
                @Override
                public void run() {
                    while (Thread.interrupted() == false) {
                        System.out.println("while正在执行");
                    }
                    System.out.println("当前线程是否中断:"+Thread.interrupted());//最后打印的为false,清除了之前的状态
                }
            });
    
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            mFuture.cancel(true);
            System.out.println(System.currentTimeMillis()-t);
        }
    
    11 线程wait 和notify/notifyall

    对象.wait(): 导致当前的线程等待,直到其他线程调用此对象的notify( ) 方法或 notifyAll( ) 方法

    对象.notify():唤醒在此对象锁上等待的单个线程

    public static void main(String[] args) {
            Object m=new Object();
            Thread thread1=new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i <20; i++) {
                        if (i==10){
                            synchronized (m){
                                try {
                                    m.wait();//假如不要m,直接调用就会报异常
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }
                        }else {
                            System.out.println(i);
                        }
                    }
                }
            });
            thread1.start();
            try {
                Thread.sleep(8000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("唤醒线程");
            synchronized (m){
                m.notify();
            }
        }
    

    注意点:
    含有wait 和notify 代码块都需要用synchronized 修饰。并且还要一样。

    12 Thread.sleep 和 Object.wait 区别

    在一个加锁了的代码块中执行Thread.sleep,不会释放锁。

    在一个加了锁的代码块中执行wait,会释放锁

    相关文章

      网友评论

          本文标题:java多线程开发知识点汇总

          本文链接:https://www.haomeiwen.com/subject/dsldpctx.html