这个方式基本不用,会影响线程的思想。
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); }
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
这个作用是什么,就是没有核心线程,有新的runnable进来,就new 一个线程执行。如果空闲线程在60s内,还没有被回收,就达到复用的目的。所以线程是存在复用的可能,但是不会等待。
ExecutorService executorService = Executors.newFixedThreadPool(2);
这个才是最常用的线程池方式。
线程调度,在池满以后等待。
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }
有一个核心线程常驻。可以保证执行顺序。FIFO
这个锁住的是this,也就是当前实例。
比如有2个方法,一个read,一个write,这个就是要加锁来解决的。
如果是2个实例,他们相互直接的synchronized是不相干的。
static synchronized 的作用域是所有的静态方法。
这个3.1.1 和3.1.2的synchronized 的作用范围不同,所以没有相关性。
static方法的使用,本质上跟class类是没有关系的,只有一个索引用以找到这个方法。所以它sync的不是所有实例对象,sync的就是这个class.name。
synchronized this 本质是在执行的过程中,加上了锁。
锁是由JVM自动取解析的。
$ javap -c SynchronizedDemo 警告: 二进制文件SynchronizedDemo包含com.demanmath.androidms.javabase.concurrent.SynchronizedDemo Compiled from "SynchronizedDemo.java" public class com.demanmath.androidms.javabase.concurrent.SynchronizedDemo { public com.demanmath.androidms.javabase.concurrent.SynchronizedDemo(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public void testA(); Code: 0: aload_0 1: dup 2: astore_1 3: monitorenter 4: iconst_0 5: istore_2 6: aload_1 7: monitorexit 8: goto 16 11: astore_3 12: aload_1 13: monitorexit 14: aload_3 15: athrow 16: return Exception table: from to target type 4 8 11 any 11 14 11 any public static synchronized void testB(); Code: 0: iconst_0 1: istore_0 2: return }
monitorenter,monitorexit 这2条指令,就是JVM控制同步的方式。
关于这两条指令的作用,我们直接参考 JVM 规范中描述:
monitorenter :Each object is associated with a monitor. A monitor is locked if and only if it has an owner. The thread that executes monitorenter attempts to gain ownership of the monitor associated with objectref, as follows:
• If the entry count of the monitor associated with objectref is zero, the thread enters the monitor and sets its entry count to one. The thread is then the owner of the monitor.
• If the thread already owns the monitor associated with objectref, it reenters the monitor, incrementing its entry count.
• If another thread already owns the monitor associated with objectref, the thread blocks until the monitor's entry count is zero, then tries again to gain ownership.
这段话的大概意思为:每个对象有一个监视器锁(Monitor),当 Monitor 被占用时就会处于锁定状态。
线程执行 Monitorenter 指令时尝试获取 Monitor 的所有权,过程如下:
如果 Monitor 的进入数为 0,则该线程进入 Monitor,然后将进入数设置为 1,该线程即为 Monitor 的所有者。
如果线程已经占有该 Monitor,只是重新进入,则进入 Monitor 的进入数加 1。
如果其他线程已经占用了 Monitor,则该线程进入阻塞状态,直到 Monitor 的进入数为 0,再重新尝试获取 Monitor 的所有权。
monitorexit:The thread that executes monitorexit must be the owner of the monitor associated with the instance referenced by objectref.
The thread decrements the entry count of the monitor associated with objectref. If as a result the value of the entry count is zero, the thread exits the monitor and is no longer its owner.
Other threads that are blocking to enter the monitor are allowed to attempt to do so.
这段话的大概意思为:执行 Monitorexit 的线程必须是 Objectref 所对应的 Monitor 的所有者。
指令执行时,Monitor 的进入数减 1,如果减 1 后进入数为 0,那线程退出 Monitor,不再是这个 Monitor 的所有者。
其他被这个 Monitor 阻塞的线程可以尝试去获取这个 Monitor 的所有权。
通过这两段描述,我们应该能很清楚的看出 Synchronized 的实现原理。
在反编译方法以后,会看到方法带有ACC_SYNCHRONIZED 标志位。
所以方法在运行的时候,获取当前方法的实例对象,进行monitor,锁住。
因此整个synchronized 作用方式就2种,对象和方法。当然静态时候 是另外2个case,所以一共4个case。