JAVA篇_多线程零碎知识总结

本文不仔细介绍多线程细节知识,而是总结一些易混淆的概念,阅读本文需要对多线程有一定了解,细节知识可以查看林炳文的博客


前置知识:

1.Runnable类和Thread类的使用,两者的关系。相同点和不同点

2.线程的状态转换

3.关键字Synchronized同步以及配套的wait(),notify()方法和notifyAll()方法

4.ReentrantLock & ReentrantReadWriteLock以及其内置的readlock和writeLock两个类的使用

5.sleep(),join(),currentThread(),yield(),wait(),notify(),notifyAll(),set/getPriority(),setName(),is/setDaemon()这些方法的作用是什么【加粗的是object方法,其他是thread方法】

ps:如果以上知识不清楚的,请查看林炳文的博客


1.sleep(),wait(),yield()方法都可以让当前线程暂停,区别如下:

sleep方法是让当前线程休眠,在休眠期间是绝对不会被调度器调用,休眠完了以后也不一定马上就执行线程,而是变为可运行(Runnable)状态,具体什么时候执行,看调度器;

yield方法是让当前线程暂停执行,重新返回到Runnable状态,然后在众多Runnable状态下的线程中(包括当前线程)选择同等级或者优先级更高的线程执行(理论上是这样,这个现象要在大批量的线程执行的时候才明显,是统计上的意义,并不是低优先级的一定不执行)。也就是当前线程可能再次被选中执行。

wait()方法是所有对象(object)的方法,,从语法角度来说就是Obj.wait(),Obj.notify必须在synchronized(Obj){...}语句块内。从功能上来说wait就是说线程在获取对象锁后,主动释放对象锁,同时本线程休眠。Thread.sleep()与Object.wait()二者都可以暂停当前线程,释放CPU控制权,主要的区别在于Object.wait()在释放CPU同时,释放了对象锁的控制


2. 对象锁(Syschronized的使用)

<工作流程> java中针对每一个对象,都有一个monitor,这个monitor的作用是监测并发代码的重入(也就是监测多线程执行同一处的代码),可以理解为监测临界资源,保证其线程安全。这个monitor在非多线程的代码处不起作用,但是在Syschronized内部(临界资源)这种会发生多线程访问的代码处就发挥作用。因为这个monitor对每个对象是唯一的,如果多个线程想要访问同一个对象的临界资源,那么只有得到这个对象的monitor使用权的才能访问,得到monitor使用权就是上锁(lock),访问期间,其他想要访问的就要排队等待(block),访问完了通过notifyAll或者notify释放锁(unlock)并通知等待的线程,然后调度器随机选择一个等待线程执行。

<总结> 每个对象唯一的monitor就是所谓的对象锁,从Syschronized开始就是上锁,一直到notifyAll或者notify调用,就是解锁。

PS:wait,notify,notifyAll都只能在Syschronized内部被调用,调用者是Syschronized(someObject)括号里面的上锁对象,wait是释放锁并暂停当前线程,但是后两者是释放锁并结束线程


3.线程池

<作用>

线程池的作用就是为了节省系统资源,降低开销产生的。用或不用都行。因为非线程池状态下,我们使用线程就会单独去开一个,用完了就销毁,这样的创建和销毁很浪费资源.线程池就可以单独开辟一个地方,执行完了的线程就回到池中等待复用(reuse),减少创建和销毁线程的开销。

<创建>

注意,下面方法都是static类方法,通过Executor类调用,返回的是ExecutorService对象

JAVA篇_多线程零碎知识总结_第1张图片

<线程池常用方法>

也就是ExecutorService类的对象的方法

添加线程到线程池:execute()方法和submit()方法,前者没有返回值,后者会返回一个Future对象,也就是线程执行的结果

关闭线程池:shutdown()和shutdownNow(),前者会等添加到线程池的线程执行完再关闭,后者不等,直接关闭

PS:添加到线程池的只能是Runnable或者Callable对象,不能直接添加Thread对象

关于线程池的更多深入的,查看林炳文的博客


4.Future,Callable,FutureTask

详细参见林炳文博客

JAVA篇_多线程零碎知识总结_第2张图片

三者其实都是一样的,都是线程的具体的执行体,被传入Thread类作为参数或者传入线程池ExecutorService去执行;

不同:

<1>Callable的call方法有返回值,返回值封装在Future对象里面,通过future对象访问结果,Runnable没有返回值。

<2>FutureTask是对Callable接口的进一步封装,继承了Runnable接口以及Future接口,既是线程的执行体,又是结果的承载体,通过自身——FutureTask对象访问结果。


前者作为参数传递给后者,后者内部是在前者的基础上添加了一个blockingQueue,解决了前者在通过Future的get方法(线程阻塞)获取结果的时候通过轮询顺序获取造成的资源浪费【参见图片】


多线程的知识框架图

JAVA篇_多线程零碎知识总结_第3张图片






你可能感兴趣的:(JAVA)