synchronized关键字和Lock:当使用线程来同时运行多个任务时,可以通过使用锁(互斥)来同步两个任务的行为,从而使得一个任务不会干涉另一个任务的资源。也就是说,如果两个任务在交替着步入某项共享资源,你可以使用互斥来使得任何时刻只有一个任务可以访问这项资源。
synchronized:在资源竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,但是ReetrantLock的性能能维持常态;在资源竞争不是很激烈的情况下,偶尔会有同步的情形下,synchronized是很合适的。原因在于,编译程序通常会尽可能的进行优化synchronize,另外可读性非常好,不管用没用过5.0多线程包的程序员都能理解。
ReentrantLock:ReentrantLock 拥有Synchronized相同的并发性和内存语义,此外还多了 锁投票,定时锁等候和中断锁等候。ReentrantLock提供了多样化的同步,比如有时间限制的同步,可以被Interrupt的同步(synchronized的同步是不能Interrupt的)等。在资源竞争不激烈的情形下,性能稍微比synchronized差点点。但是当同步非常激烈的时候,synchronized的性能一下子能下降好几十倍。而ReentrantLock确还能维持常态。
ReentrantLock获取锁定与三种方式:
lock(), 如果获取了锁立即返回,如果别的线程持有锁,当前线程则一直处于休眠状态,直到获取锁。
tryLock(), 如果获取了锁立即返回true,如果别的线程正持有锁,立即返回false。
tryLock(long timeout,TimeUnit unit), 如果获取了锁定立即返回true,如果别的线程正持有锁,会等待参数给定的时间,在等待的过程中,如果获取了锁定,就返回true,如果等待超时,返回false。
lockInterruptibly:如果获取了锁定立即返回,如果没有获取锁定,当前线程处于休眠状态,直到或者锁定,或者当前线程被别的线程中断。
Atomic:和上面的类似,不激烈情况下,性能比synchronized略逊,而激烈的时候,也能维持常态。激烈的时候,Atomic的性能会优于ReentrantLock一倍左右。但是其有一个缺点,就是只能同步一个值,一段代码中只能出现一个Atomic的变量,多于一个同步无效。因为他不能在多个Atomic之间同步。
线程A和B都要获取对象O的锁定,假设A获取了对象O锁,B将等待A释放对O的锁定,如果使用synchronized ,如果A不释放,B将一直等下去,不能被中断。如果使用ReentrantLock,如果A不释放,可以使B在等待了足够长的时间以后,中断等待,而干别的事情。
synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定,但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将unLock()放到finally{}中
Object的方法wait()和notify()或者Condition的await()和signal()方法:任务彼此之间协作一起去解决某个问题,在解决这个问题中,由于某些部分必须在其他部分被解决之前解决。
wait():使一个线程处于等待状态,并且释放所持有的对象的lock。会在等待外部世界产生变化时将任务挂起,并且只有在notify或notifyAll发生时,这个任务才会被唤醒病区检查所产生的变化。因此,wait()提供了一种在任务之间对活动同步的方式。
sleep():使一个正在运行的线程处于睡眠状态,是Thread的一个静态方法,调用此方法需要捕捉InterruptedException异常,没有释放锁。
notify():在众多等待同一个锁的任务中只有一个会被唤醒。注意的是在调用此方法时,并不能确切的唤醒某一个等待的线程,而是有JVM确定唤醒哪个线程,而不是按优先级。
notifyAll():将唤醒所有正在等待的任务。当notifyAll()因某个特定所而被调用时,只有等待这个锁的任务才会被唤醒,注意不是给所有唤醒线程一个对象的锁,而是让它们竞争。 |
|