java多线程开发知识点汇总

2019-10-03  本文已影响0人  过期的薯条

1.引言

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

2.正题

1.线程的状态
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,会释放锁

上一篇下一篇

猜你喜欢

热点阅读