多线程基础知识

笔记很多地方都是摘抄, 以下为部分摘抄出处
Java的wait()、notify()学习三部曲之一:JVM源码分析

多线程脑图

一、乐观锁与悲观锁

1.1 悲观锁

  对数据的修改持有悲观态度的并发控制方式, 总是假设最坏的情况, 每次读取数据的时候都默认其他线程会更改数据, 因此需要进行加锁操作, 当其他线程想要访问数据时, 都需要阻塞挂起
  适用写多读少的场景

1.2 乐观锁

  乐观锁假设数据一般情况下不会造成冲突, 所以在数据进行提交更新时, 才会正式对数据的冲突与否进行检测, 如果发现冲突了, 则返回给用户错误的信息, 让用户决定如何去做.
  适用读多邪少的场景

1.3 悲观锁与乐观锁对比

  • 1、乐观锁适用于读多写少的场景, 提高程序的吞吐量
  • 2、悲观锁适用于写多读少的场景
  • 3、乐观锁主要步骤: 冲突检测和数据更新, 例如CAS
  • 4、悲观锁可以用行锁、表锁、读锁、写锁等, 都是在操作之前先上锁; java里面的同步synchronized关键字的实现

二、锁优化

2.1 自旋锁与自适应锁

1、自旋锁
  JDK1.4.2引入, 默认关闭, JDK1.6默认开启, 自旋不能代替阻塞
  优点: 避免线程频繁切换的开销
  缺点: 如果自旋时间过长, 会导致CPU被长时间占用, 性能损耗
2、自适应自旋
  JDK1.6引入
  自适应意味着自旋的时间不再固定了, 而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定

2.2 锁消除

  虚拟机即时编译器在运行时, 对一些代码上要求同步, 但是被检测到不可能存在共享数据竞争的锁进行消除
  锁消除的主要判断依据来源于逃逸分析的数据支持, 如果判断在一段代码中, 堆上的所有数据都不会逃逸出去而是被其他线程访问到, 那就可以把它们当做栈上数据对待, 认为它们是线程私有的, 同步加锁自然就无须进行

2.3 锁粗化

  如果虚拟机探测到有这样一串零碎的操作都对同一个对象加锁, 将会把加锁同步的范围扩展(粗化)到整个操作序列的外部

2.4 轻量级锁

  轻量级锁能提升程序同步性能的依据是"对于绝大部分的锁, 在整个同步周期内都是不存在竞争的", 这是一个经验数据. 如果没有竞争, 轻量级锁使用了CAS操作避免了使用互斥量的开销, 但如果存在锁竞争, 除了互斥量的开销外, 还额外发生了CAS操作, 因此在有竞争的情况下, 轻量级锁会比传统的重量级锁更慢.

2.5 偏向锁

  目的: 消除数据在无竞争情况下的同步原语, 进一步提高程序的运行性能.
  如果说轻量级锁是在无竞争的情况下使用CAS操作去消除同步使用的互斥量, 那偏向锁就是在无竞争的情况下把整个同步都消除掉, 连CAS操作都不作了.
  锁偏向第一个获得它的线程, 如果在接下来的执行过程中, 该锁没有被其他线程获取, 则持有偏向锁的线程将永远不需要再进行同步
  当有另外一个线程去尝试获取这个锁时, 偏向模式宣告结束.

三、公平锁与非公平锁

3.1 公平锁

  多个线程按照申请锁的顺序去获得锁, 线程会直接进入队列去排队, 永远都是队列的第一位才能得到锁

优点: 所有的线程都能得到资源, 不会饿死在队列中
缺点: 吞吐量会下降很多, 队列里面除了第一个线程, 其他的线程都会阻塞, CPU唤醒阻塞线程的开销会很大

3.2 非公平锁

  多个线程去获取锁的时候, 会直接尝试获取, 获取不到, 再去进入到等待队列, 如果能获取到, 就直接获取到锁
优点: 可以减少CPU唤醒线程的开销, 整体的吞吐效率会高点, CPU也不必去唤醒所有线程, 会减少唤起线程的数量
缺点: 可能导致队列中间的线程一直获取不到锁或者长时间获取不到锁, 导致饿死

3.3 NonfairSync与FairSync

  两者区别在于公平锁先判断等待队列中是否有数据, 而非公平锁尝试直接获取锁

3.3.1 NonfairSync.tryAcquire

protected final boolean tryAcquire(int acquires) {
	return nonfairTryAcquire(acquires);
}
final boolean nonfairTryAcquire(int acquires) {
	final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {
		if (compareAndSetState(0, acquires)) {
			setExclusiveOwnerThread(current);
            return true;
        }
    }
    else if (current == getExclusiveOwnerThread()) {
        int nextc = c + acquires;
        if (nextc < 0) // overflow
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    return false;
}

3.3.2 FairSync.tryAcquire

protected final boolean tryAcquire(int acquires) {
	final Thread current = Thread.currentThread();
	int c = getState();
	if (c == 0) {
		if (!hasQueuedPredecessors() &&
			compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    else if (current == getExclusiveOwnerThread()) {
		int nextc = c + acquires;
        if (nextc < 0)
        	throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
	}
	return false;
}

四、yield、sleep、join

4.1 yield与sleep共同点

  释放CPU, 但是不会释放锁

4.2 yield

  释放CPU, 但是很可能又会再次获取到CPU执行权

JVM_ENTRY(void, JVM_Yield(JNIEnv *env, jclass threadClass))
  JVMWrapper("JVM_Yield");
  //检查是否设置了DontYieldALot参数,默认为fasle
  //如果设置为true,直接返回
  if (os::dont_yield()) return;
 //如果ConvertYieldToSleep=true(默认为false),调用os::sleep,否则调用os::yield
  if (ConvertYieldToSleep) {
    os::sleep(thread, MinSleepInterval, false);//sleep 1ms
  } else {
    os::yield();
  }
JVM_END

void os::yield() {
  sched_yield();
}

sched_yield函数总结: sched_yield是Linux kernel提供的API, 它会使用调用线程放弃CPU使用权, 加入到同等优先级队列的末尾, 如果调用线程是优先级最高的唯一线程, yield方法返回后, 调用线程会继续执行

4.3 Thread.sleep

  跟着别人的文章看jvm层面的源码也没怎么看明白, 索性就直接复制粘贴过来, 原文章出处 java线程源码解析之yield和sleep

总结流程:

  • 1、参数校验
  • 2、调用sleep之前发现如果线程已经中断, 抛出中断异常
  • 3、设置线程状态为SLEEPING
  • 4、保存线程初始化状态, 返回时恢复原状态
  • 5、调用os:sleep方法, 如果发生中断, 抛出异常
  • 6、在条件变量上等待
  • 7、恢复Thread原状态
JVM_ENTRY(void, JVM_Sleep(JNIEnv* env, jclass threadClass, jlong millis))
  JVMWrapper("JVM_Sleep");

  if (millis < 0) {//参数校验
    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "timeout value is negative");
  }

  //如果线程已经中断,抛出中断异常,关于中断的实现,在另一篇文章中会讲解
  if (Thread::is_interrupted (THREAD, true) && !HAS_PENDING_EXCEPTION) {
    THROW_MSG(vmSymbols::java_lang_InterruptedException(), "sleep interrupted");
  }
 //设置线程状态为SLEEPING
  JavaThreadSleepState jtss(thread);

  EventThreadSleep event;

  if (millis == 0) {
    //如果设置了ConvertSleepToYield(默认为true),和yield效果相同
    if (ConvertSleepToYield) {
      os::yield();
    } else {//否则调用os::sleep方法
      ThreadState old_state = thread->osthread()->get_state();
      thread->osthread()->set_state(SLEEPING);
      os::sleep(thread, MinSleepInterval, false);//sleep 1ms
      thread->osthread()->set_state(old_state);
    }
  } else {//参数大于0
   //保存初始状态,返回时恢复原状态
    ThreadState old_state = thread->osthread()->get_state();
    //osthread->thread status mapping:
    // NEW->NEW
    //RUNNABLE->RUNNABLE
    //BLOCKED_ON_MONITOR_ENTER->BLOCKED
    //IN_OBJECT_WAIT,PARKED->WAITING
    //SLEEPING,IN_OBJECT_WAIT_TIMED,PARKED_TIMED->TIMED_WAITING
    //TERMINATED->TERMINATED
    thread->osthread()->set_state(SLEEPING);
    //调用os::sleep方法,如果发生中断,抛出异常
    if (os::sleep(thread, millis, true) == OS_INTRPT) {
      if (!HAS_PENDING_EXCEPTION) {
        if (event.should_commit()) {
          event.set_time(millis);
          event.commit();
        }
        THROW_MSG(vmSymbols::java_lang_InterruptedException(), "sleep interrupted");
      }
    }
    thread->osthread()->set_state(old_state);//恢复osThread状态
  }
  if (event.should_commit()) {
    event.set_time(millis);
    event.commit();
  }
JVM_END

4.3.1 os::sleep

int os::sleep(Thread* thread, jlong millis, bool interruptible) {
  assert(thread == Thread::current(),  "thread consistency check");
  //线程有如下几个成员变量:
  //ParkEvent * _ParkEvent ;          // for synchronized()
  //ParkEvent * _SleepEvent ;        // for Thread.sleep
  //ParkEvent * _MutexEvent ;      // for native internal Mutex/Monitor
  //ParkEvent * _MuxEvent ;         // for low-level muxAcquire-muxRelease
  ParkEvent * const slp = thread->_SleepEvent ;
  slp->reset() ;
  OrderAccess::fence() ;

//如果millis>0,传入interruptible=true,否则为false
  if (interruptible) {
    jlong prevtime = javaTimeNanos();

    for (;;) {
      if (os::is_interrupted(thread, true)) {//判断是否中断
        return OS_INTRPT;
      }

      jlong newtime = javaTimeNanos();//获取当前时间
      //如果linux不支持monotonic lock,有可能出现newtime<prevtime
      if (newtime - prevtime < 0) {
        assert(!Linux::supports_monotonic_clock(), "time moving backwards");
      } else {
        millis -= (newtime - prevtime) / NANOSECS_PER_MILLISEC;
      }

      if(millis <= 0) {
        return OS_OK;
      }

      prevtime = newtime;
      {
        assert(thread->is_Java_thread(), "sanity check");
        JavaThread *jt = (JavaThread *) thread;
        ThreadBlockInVM tbivm(jt);
        OSThreadWaitState osts(jt->osthread(), false );

        jt->set_suspend_equivalent();
        slp->park(millis);
        jt->check_and_wait_while_suspended();
      }
    }
  } else {//如果interruptible=false
   //设置osthread的状态为CONDVAR_WAIT
    OSThreadWaitState osts(thread->osthread(), false );
    jlong prevtime = javaTimeNanos();

    for (;;) {
      jlong newtime = javaTimeNanos();

      if (newtime - prevtime < 0) {
        assert(!Linux::supports_monotonic_clock(), "time moving backwards");
      } else {
        millis -= (newtime - prevtime) / NANOSECS_PER_MILLISEC;
      }

      if(millis <= 0) break ;

      prevtime = newtime;
      slp->park(millis);//底层调用pthread_cond_timedwait实现
    }
    return OS_OK ;
  }
}

4.3.2 PlatformEvent::park

void os::PlatformEvent::park() { 
    ...
    //锁住信号量
    int status = pthread_mutex_lock(_mutex);
    while (_Event < 0) {
      //释放信号量,并在条件变量上等待
      status = pthread_cond_wait(_cond, _mutex);
    }
    //释放信号量
    status = pthread_mutex_unlock(_mutex);
}

4.4 Thread.join

作用: 阻塞Thread.join调用者的线程, 直到Thread执行完毕之后, 调用者线程被唤醒

4.4.1 demo

三个线程循环依次打印ABC

public static void test() {
	try {
		test1();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
private static class JoinDemo extends Thread {
    public String num;
    public String curThread;

    public JoinDemo(String curThread, String num) {
        this.curThread = curThread;
        this.num = num;
    }

    @Override
    public void run() {
        Log.v("AndroidTest", "curThread = " + curThread + ", num = " + num);
    }
}

4.4.2 Thread.join原理

public final void join(long millis) throws InterruptedException {
    synchronized(lock) {
        long base = System.currentTimeMillis();
        long now = 0;
        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }
        if (millis == 0) {
            while (isAlive()) {
            	//对应上面的demo, 当t1.join执行时, 阻塞的是main线程
                lock.wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                lock.wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }
}

4.4.3 被阻塞的线程何时被唤醒

void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
	// 唤醒处于等待的线程对象, 线程终止之后做的清理工作
	ensure_join(this); 
}

static void ensure_join(JavaThread* thread) {
  // We do not need to grap the Threads_lock, since we are operating on ourself.
  Handle threadObj(thread, thread->threadObj());
  assert(threadObj.not_null(), "java thread object must exist");
  ObjectLocker lock(threadObj, thread);
  // Ignore pending exception (ThreadDeath), since we are exiting anyway
  thread->clear_pending_exception();
  // Thread is exiting. So set thread_status field in  java.lang.Thread class to TERMINATED.
  java_lang_Thread::set_thread_status(threadObj(), java_lang_Thread::TERMINATED);
  // Clear the native thread instance - this makes isAlive return false and allows the join()
  // to complete once we've done the notify_all below
  //这里是清除native线程,这个操作会导致isAlive()方法返回false
  java_lang_Thread::set_thread(threadObj(), NULL);
  // 唤醒所有等待锁的线程
  lock.notify_all(thread);
  // Ignore pending exception (ThreadDeath), since we are exiting anyway
  thread->clear_pending_exception();
}

五、synchronized、notify、wait

流程超级复杂, 只背关键点的流程

5.1 synchronized、notify、wait demo

public class WaitNotifyDemo {
    private final Object lock = new Object();

    private static void sleep(long time) {
        SystemClock.sleep(time);
    }

    private void log(String desc) {
        Log.v("AndroidTest", "thread = " + Thread.currentThread().getName() + ":" + desc);
    }

    public void startThreadA() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock) {
                    log("get lock");
                    startThreadB();
                    log("start wait");
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    log("get lock after wait");
                    log("release lock");
                }
            }
        }, "thread-A").start();
    }

    private void startThreadB() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock) {
                    log("get lock");
                    startThreadC();
                    sleep(100);
                    log("start notify");
                    lock.notify();
                    log("release lock");
                }
            }
        }, "thread-B").start();
    }

    private void startThreadC() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock) {
                    log("get lock");
                    log("release lock");
                }
            }
        }, "thread-c").start();
    }
}

执行
new new WaitNotifyDemo().startThreadA();
日志输出
thread = thread-A:get lock
thread = thread-A:start wait
thread = thread-B:get lock
thread = thread-B:start notify
thread = thread-B:release lock
thread = thread-A:get lock after wait
thread = thread-A:release lock
thread = thread-c:get lock
thread = thread-c:release lock

5.2 结合日志梳理流程

  • 1、启动线程A, 取得锁之后先启动线程B再执行wait()方法, 释放锁并等待
  • 2、线程B启动之后会等待锁, A线程执行wait()之后, 线程B取得锁, 然后启动线程C, 再执行notify唤醒线程A, 最后退出synchronized代码块, 释放锁
  • 3、线程C启动之后就一直等待锁, 这时线程B还没有退出synchronized代码块, 锁还在线程B手里
  • 4、线程A在线程B执行notify之后就一直在等待锁, 这时线程B还没有退出synchronized代码块, 锁还在线程B手里
  • 5、线程B退出synchronized代码块, 释放锁之后, 线程A和线程C竞争锁.

5.3 根据demo列出所有问题点

  • 1、demo反复执行多次, 结果都是B释放锁之后A会先得到锁, 为什么C不能先得到锁?
  • 2、线程A在wait()的时候做了什么?
  • 3、线程C启动后, 由于此时线程B持有锁, 那么线程C此时在干啥?
  • 4、线程B在notify()的时候做了什么?
  • 5、线程B释放锁的时候做了什么?

5.4 问题点一次分析

分析之前记录一笔重要的备注: ObjectWaiter对象存在于WaitSet (等待队列)、EntryList (同步队列)、cxq (同步队列) 等集合中, 或者正在这些集合中移动

5.4.1 synchronized流程

  • 1、首先判断偏向锁是否可用, 如果可用, 直接进入. 多线程竞争的情况下偏向锁失效, 所以走非偏向锁逻辑
  • 2、非偏向锁流程 是否处于无锁状态, 无锁状态通过CAS去竞争锁
  • 3、有锁状态, 且锁非当前线程持有, 构造ObjectMonitor对象去竞争锁
  • 4、竞争锁失败就将线程加入_cxq队列的首位
  • 5、开始无限循环, 竞争锁成功就退出循环, 竞争失败线程挂起, 等待被唤醒后继续竞争
  • 6、备注: 这里的竞争分两种情况, 如果自旋可用, 执行Self->_ParkEvent->park(time)挂起time时间后自动唤醒, 如果自旋失效, 执行Self->_ParkEvent->park()进行永久挂起, 直到外界唤醒

5.4.2 monitorenter流程

javapjava文件synchronized对应monitorenter指令, 而monitorenter指令对应源码如下

IRT_ENTRY_NO_ASYNC(void, InterpreterRuntime::monitorenter(JavaThread* thread, BasicObjectLock* elem))
#ifdef ASSERT
  thread->last_frame().interpreter_frame_verify_monitor(elem);
#endif
  if (PrintBiasedLockingStatistics) {
    Atomic::inc(BiasedLocking::slow_path_entry_count_addr());
  }
  Handle h_obj(thread, elem->obj());
  assert(Universe::heap()->is_in_reserved_or_null(h_obj()),
         "must be NULL or an object");
  // 判断是否使用偏向锁, 根据偏向锁的定义, 多线程竞争时, 偏向锁失效, 所以流程向下看
  if (UseBiasedLocking) {
    // Retry fast entry if bias is revoked to avoid unnecessary inflation
    ObjectSynchronizer::fast_enter(h_obj, elem->lock(), true, CHECK);
  } else {
    ObjectSynchronizer::slow_enter(h_obj, elem->lock(), CHECK);
  }
  assert(Universe::heap()->is_in_reserved_or_null(elem->obj()),
         "must be NULL or an object");
#ifdef ASSERT
  thread->last_frame().interpreter_frame_verify_monitor(elem);
#endif
IRT_END

5.4.3 slow_enter流程

void ObjectSynchronizer::slow_enter(Handle obj, BasicLock* lock, TRAPS) {
  markOop mark = obj->mark();
  assert(!mark->has_bias_pattern(), "should not see bias pattern here");

  //是否处于无锁状态
  if (mark->is_neutral()) {
    // Anticipate successful CAS -- the ST of the displaced mark must
    // be visible <= the ST performed by the CAS.
    lock->set_displaced_header(mark);
    //无锁状态就去竞争锁
    if (mark == (markOop) Atomic::cmpxchg_ptr(lock, obj()->mark_addr(), mark)) {
      TEVENT (slow_enter: release stacklock) ;
      return ;
    }
    // Fall through to inflate() ...
  } else
  if (mark->has_locker() && THREAD->is_lock_owned((address)mark->locker())) {
    //如果处于有锁状态,就检查是不是当前线程持有锁,如果是当前线程持有的,就return,然后就能执行同步代码块中的代码了
    assert(lock != mark->locker(), "must not re-lock the same lock");
    assert(lock != (BasicLock*)obj->mark(), "don't relock with same BasicLock");
    lock->set_displaced_header(NULL);
    return;
  }

#if 0
  // The following optimization isn't particularly useful.
  if (mark->has_monitor() && mark->monitor()->is_entered(THREAD)) {
    lock->set_displaced_header (NULL) ;
    return ;
  }
#endif

  // The object header will never be displaced to this lock,
  // so it does not matter what the value is, except that it
  // must be non-zero to avoid looking like a re-entrant lock,
  // and must not look locked either.
  lock->set_displaced_header(markOopDesc::unused_mark());
  //锁膨胀
  ObjectSynchronizer::inflate(THREAD, obj())->enter(THREAD);
}

5.4.3 enter

在这里插入图片描述

5.5 Object.wait()

5.5.1 wait流程

  • 1、包装成ObjectWaiter对象, 状态为TS_WAIT
  • 2、构造ObjectWaiter对象, 放入_WaitSet中 (_WaitSet是一个环形双向链表结构)
  • 3、释放锁、唤醒等待线程
  • 4、挂起自己
  • 5、如果被唤醒后, 执行获取锁的流程

5.5.2 wait

void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) {
   ...

   if (interruptible && Thread::is_interrupted(Self, true) && !HAS_PENDING_EXCEPTION) {
     ...
     //调用wait 的时候线程可以被中断
     THROW(vmSymbols::java_lang_InterruptedException());
     return ;
   }

   //构造节点,封装了当前线程
   ObjectWaiter node(Self);
   //节点状态为TS_WAIT
   node.TState = ObjectWaiter::TS_WAIT ;
   Self->_ParkEvent->reset() ;
   OrderAccess::fence();          // ST into Event; membar ; LD interrupted-flag

   //操作等待队列需要获取锁
   Thread::SpinAcquire (&_WaitSetLock, "WaitSet - add") ;
   //将当前节点加入等待队列里------->(1)
   AddWaiter (&node) ;
   //释放等待队列的锁
   Thread::SpinRelease (&_WaitSetLock) ;
   ...
   //释放锁+唤醒线程------->(2)
   exit (true, Self) ;                    // exit the monitor
   ...
   { // State transition wrappers
     OSThread* osthread = Self->osthread();
     OSThreadWaitState osts(osthread, true);
     {
       ...
       if (interruptible && (Thread::is_interrupted(THREAD, false) || HAS_PENDING_EXCEPTION)) {
           // Intentionally empty
       } else
       if (node._notified == 0) {
         //挂起自己------->(3)
         if (millis <= 0) {
            Self->_ParkEvent->park () ;
         } else {
            ret = Self->_ParkEvent->park (millis) ;
         }
       }
       ...
     } // Exit thread safepoint: transition _thread_blocked -> _thread_in_vm
     //这之后是线程被唤醒后的操作
     ...
     ObjectWaiter::TStates v = node.TState ;
     if (v == ObjectWaiter::TS_RUN) {
         //正常获取锁的流程
         enter (Self) ;
     } else {
         //此时v的状态是在同步队列里--------------->(4)
         ReenterI (Self, &node) ;
         node.wait_reenter_end(this);
     }
     ...
   } // OSThreadWaitState()
}

5.5.3 AddWaiter

#ObjectMonitor.cpp
inline void ObjectMonitor::AddWaiter(ObjectWaiter* node) {
  if (_WaitSet == NULL) {
   //等待队列里没有节点,则当前节点被当作头节点
    _WaitSet = node;
    node->_prev = node;
    node->_next = node;
  } else {
   //节点插入到队列尾部
    ObjectWaiter* head = _WaitSet ;
    ObjectWaiter* tail = head->_prev;
    assert(tail->_next == head, "invariant check");
    tail->_next = node;
    head->_prev = node;
    node->_next = head;
    node->_prev = tail;
  }
}

5.6 notify

5.6.1 notify流程

  • 1、QMode默认0, Policy默认2
  • 2、将节点从等待队列_WaitSet中移除, Policy默认为2, 所以移动到同步队列_EntryList首部
  • 3、重点: 下面的逻辑并不是notify的逻辑, notify并不会释放锁, 只是将节点从_WaitSet移动到_EntryList首部
  • 4、释放锁
  • 5、唤醒线程: QMode = 0, 取出_EntryList中的头部节点并唤醒, 如果_EntryList = null, 将_EntryList指向_cxq, 并取出头部节点唤醒

5.6.2 notify

void ObjectMonitor::notify(TRAPS) {
   ...
  if (_WaitSet == NULL) {
   //等待队列为空,直接返回
     return ;
  }
  //notify 策略,默认是2
  int Policy = Knob_MoveNotifyee ;

  //获取操作等待队列的锁
  Thread::SpinAcquire (&_WaitSetLock, "WaitSet - notify") ;
  //将队头节点移出队列-------->(1)
  ObjectWaiter * iterator = DequeueWaiter() ;
  if (iterator != NULL) {
     ...
     ObjectWaiter * List = _EntryList ;
     if (Policy == 2) {      // prepend to cxq
         // 默认策略-------------->(2)
         if (List == NULL) {
            //_EntryList 为空,则将节点插入到_EntryList 头
             iterator->_next = iterator->_prev = NULL ;
             _EntryList = iterator ;
         } else {
            //修改状态为TS_CXQ
            iterator->TState = ObjectWaiter::TS_CXQ ;
            for (;;) {
                ObjectWaiter * Front = _cxq ;
                iterator->_next = Front ;
                //插入到_cxq头部
                if (Atomic::cmpxchg_ptr (iterator, &_cxq, Front) == Front) {
                    break ;
                }
            }
         }
     }
     ...
  }
  //释放等待队列的锁
  Thread::SpinRelease (&_WaitSetLock) ;
  ...
}

5.6.3 exit

void ATTR ObjectMonitor::exit(bool not_suspended, TRAPS) {
	// QMode == 0 
	_EntryList = w ;
    ObjectWaiter * q = NULL ;
    ObjectWaiter * p ;
    //该循环的目的是为了将_EntryList里的节点前驱连接起来---------(3)
    for (p = w ; p != NULL ; p = p->_next) {
        guarantee (p->TState == ObjectWaiter::TS_CXQ, "Invariant") ;
        //改为ENTER状态
        p->TState = ObjectWaiter::TS_ENTER ;
        p->_prev = q ;
        q = p ;
    }
    //释放锁---------(4)
    ExitEpilog (Self, w) ;
}

5.6.4 ExitEpilog

void ObjectMonitor::ExitEpilog (Thread * Self, ObjectWaiter * Wakee) {
   //从队列节点里取出ParkEvent
   ParkEvent * Trigger = Wakee->_event ;
   Wakee  = NULL ;

   //释放锁,将_owner置空
   OrderAccess::release_store_ptr (&_owner, NULL) ;
   OrderAccess::fence() ;                               // ST _owner vs LD in unpark()
   //唤醒节点里封装的线程
   Trigger->unpark() ;
}

六、volatile与CAS

volatile: 保证可见性与禁止指令重排序

CAS: 本质利用CPU的比较并交换指令

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值