Código-fonte OpenJDK detalhado - como implementar o efeito retardado do bloqueio de polarização

Com relação ao bloqueio de polarização, incluindo desfazer e redirecionar, já analisamos o código-fonte antes, então não vou entrar em detalhes aqui, e principalmente olhar para a questão do atraso na entrada em vigor. Além disso, a maior parte do código-fonte postado neste artigo mantém apenas a lógica da preocupação atual.

  Sabemos que a máquina virtual nos fornece o parâmetro-XX: + UseBIASLocking para ligar ou desligar a otimização do bloqueio de polarização (o padrão é ativado), mas a ativação do bloqueio de polarização tem um tempo de atraso padrão, que pode ser definido pelo parâmetro-XX: BiasLockingStartupDelay, o padrão é 4 segundos, você pode encontrar a configuração padrão em globals.hpp:

  product(intx, BiasedLockingStartupDelay, 4000,"Number of milliseconds to wait before enabling biased locking")

  Este artigo irá para o nível do código-fonte para ver como esse atraso é implementado. Sem muita bobagem, vamos direto ao tópico ~

Análise de código fonte

  Digite bIASLocking.cpp para ver a lógica de inicialização do bloqueio polarizado:

void BiasedLocking::init() {
    
    
  if (UseBiasedLocking) {
    
    
  	//启用偏向锁
    if (BiasedLockingStartupDelay > 0) {
    
    
	  //需要延时生效,默认4000ms
      EnableBiasedLockingTask* task = new EnableBiasedLockingTask(BiasedLockingStartupDelay);
      //调用enroll注册任务
      task->enroll();
    } else {
    
    
      //否则立即调用VM_EnableBiasedLocking 开启偏向锁
      VM_EnableBiasedLocking op(false);
      VMThread::execute(&op);
    }
  }
}

  Em primeiro lugar, UseBIASLocking é verdadeiro, indicando que o bloqueio tendencioso está ativado. Se BiasLockingStartupDelay for maior que 0, significa que um atraso é necessário para entrar em vigor. Aqui está um EnableBisedLockingTask, vamos dar uma olhada na definição desta tarefa:

class EnableBiasedLockingTask : public PeriodicTask {
    
    
 public:
  EnableBiasedLockingTask(size_t interval_time) : PeriodicTask(interval_time) {
    
    }
  //这个方法这时先不管,后面调用的时候再说
  virtual void task() {
    
    
    VM_EnableBiasedLocking *op = new VM_EnableBiasedLocking(true);
    VMThread::execute(op);
  }
};

  Pode ser visto que EnableBisedLockingTask é uma classe derivada de PeriodicTask. O construtor de parâmetro da classe pai é chamado com o parâmetro interval_time. PeriodicTask é definido em task.hpp, e o construtor é implementado em task.cpp:

PeriodicTask::PeriodicTask(size_t interval_time) :
  _counter(0), _interval((int) interval_time) {
    
    
}

  O interval_time é atribuído ao atributo _interval, _interval é uma constante privada, em milissegundos, e _counter é definido como 0:

class PeriodicTask: public CHeapObj<mtInternal> {
    
    
private:
  int _counter;
  const int _interval;
}

  Até agora, um EnableBulationsLockingTask (uma classe derivada de PeriodicTask) foi criado. Depois de criado, o método task-> matricula () é chamado, o qual é definido na classe pai PeriodicTask:

void enroll();

  Encontre a implementação deste método em task.cpp:

void PeriodicTask::enroll() {
    
    
  MutexLockerEx ml(PeriodicTask_lock->owned_by_self() ?
                     NULL : PeriodicTask_lock);
  _tasks[_num_tasks++] = this;
  WatcherThread* thread = WatcherThread::watcher_thread();
  if (thread) {
    
    
    thread->unpark();
  } else {
    
    
    WatcherThread::start();
  }
}

  Pode ser visto que um objeto WatcherThread é finalmente usado. WatcherThread é uma classe derivada do objeto Thread. É definido em thread.hpp. Nenhum código será postado aqui, caso contrário, ele irá divagar ~ Vamos diretamente para WatcherThread :: run (). Veja, basta postar duas linhas de código:

void WatcherThread::run() {
    
    
	......
	int time_waited = sleep();
	......
	PeriodicTask::real_time_tick(time_waited);
	......
}

  Então, vamos dar uma olhada na implementação do método PeriodicTask :: real_time_tick (time_waited), onde o código principal é:

for(int index = 0; index < _num_tasks; index++) {
    
    
	 _tasks[index]->execute_if_pending(delay_time);
}

  Anteriormente, chamamos o método PeriodicTask :: register () para registrar o EnableBIASLockingTask na matriz _tasks. Aqui, percorreremos as tarefas de _tasks e chamaremos o método execute_if_pending respectivamente, que é definido na classe pai PeriodicTask:

 void execute_if_pending(int delay_time) {
    
    
    // make sure we don't overflow
    jlong tmp = (jlong) _counter + (jlong) delay_time;
    if (tmp >= (jlong) _interval) {
    
    
      _counter = 0;
      task();
    } else {
    
    
      _counter += delay_time;
    }
  }

  Quando o julgamento atingir o tempo _interval, o método task () será chamado. O método task () é definido no método EnableBIASLockingTask, então vamos dar a volta e retornar para EnableBIASLockingTask:

class EnableBiasedLockingTask : public PeriodicTask {
    
    
 public:
  EnableBiasedLockingTask(size_t interval_time) : PeriodicTask(interval_time) {
    
    }

  virtual void task() {
    
    
    //实际上是一个VM_Operation
    VM_EnableBiasedLocking *op = new VM_EnableBiasedLocking(true);
    VMThread::execute(op);
  }
};

  A lógica do método de tarefa é relativamente simples: primeiro, um objeto VM_EnableBIASLocking é gerado. É uma classe derivada da classe VM_Operation , que implementa a lógica do método doit , e executa esta operação através de VMThread :: execute (se a configuração não tiver efeito com atraso, esta lógica será executada quando o bloqueio de polarização for inicializado) e, finalmente, o método doit ():

class VM_EnableBiasedLocking: public VM_Operation {
    
    
 public:
  void doit() {
    
    
    SystemDictionary::classes_do(enable_biased_locking);
    _biased_locking_enabled = true;
  }
};

  O método doit chama principalmente o método SystemDictionary :: classes_do. Voltaremos mais tarde para ver o que é enale_bias_locking. Agora vamos ver o que o método SystemDictionary :: classes_do faz:

void SystemDictionary::classes_do(void f(Klass*)) {
    
    
  dictionary()->classes_do(f);
}

  É muito claro aqui, classes_do recebe um ponteiro de função, a função dictionary () retornará as classes carregadas e essas classes carregadas serão armazenadas nos membros estáticos de SystemDictionary na forma de Dictionary:

static Dictionary*            _dictionary;

  Este dicionário é uma classe derivada de TwoOopHashtable :

class Dictionary : public TwoOopHashtable<Klass*, mtClass> {
    
    
}

  Aqui, não precisamos nos preocupar muito com essa estrutura de dados, só precisamos saber que a função dictionary () retornará as classes carregadas e, em seguida, chamará as funções passadas nessas classes. Você pode observar a implementação do função classes_do, que é implementada em dictionary.cpp:

void Dictionary::classes_do(void f(Klass*)) {
    
    
  for (int index = 0; index < table_size(); index++) {
    
    
    for (DictionaryEntry* probe = bucket(index);
                          probe != NULL;
                          probe = probe->next()) {
    
    
      Klass* k = probe->klass();
      if (probe->loader_data() == InstanceKlass::cast(k)->class_loader_data()) {
    
    
        f(k);
      }
    }
  }
}

  É para percorrer todas as classes carregadas, chamar a função passada e passar cada Klass percorrida como um parâmetro. Neste ponto, podemos voltar ao método doit () de VM_EnableBIASLocking, ou seja, dar uma olhada nesta linha de código:

SystemDictionary::classes_do(enable_biased_locking);

  Após a análise anterior, sabemos que SystemDictionary :: classes_do receberá um ponteiro de função, percorrerá todas as classes carregadas e, em seguida, chamará a função com a classe (Klass) como parâmetro de entrada. Então, esse enable_bias_locking deve ser um ponteiro de função. Na verdade, voltamos a biaseLocking.cpp para encontrar a definição desta função:

static void enable_biased_locking(Klass* k) {
    
    
  k->set_prototype_header(markOopDesc::biased_locking_prototype());
}

  Rastreie aqui, tudo ficará claro. Há uma propriedade markOop type _prototype_header no Klass, que pode ser usada para indicar a ativação / desativação do bloqueio de polarização do objeto, que é definido em Klass.hpp:

class Klass : public Metadata {
    
    
 protected:
 	markOop  _prototype_header;
}

  Já que o método set_prototype_header () é um método embutido, a implementação específica está em klass.inline.hpp:

inline void Klass::set_prototype_header(markOop header) {
    
    
  _prototype_header = header;
}

  Como você pode ver, a propriedade _prototype_header é definida para o markOop especificado, então o que exatamente é esse markOop agora? Não sei se alguns amigos já têm um sentimento familiar ~ Volte para o método enable_bIAS_locking de biaseLocking.cpp novamente:

static void enable_biased_locking(Klass* k) {
    
    
  k->set_prototype_header(markOopDesc::biased_locking_prototype());
}

  Vamos dar uma olhada no markOop específico retornado por markOopDesc ​​:: bIAS_locking_prototype (). Vá para markOop.h e encontre o método bised_locking_prototype:

static markOop biased_locking_prototype() {
    
    
    return markOop( biased_lock_pattern );
  }

  Veja a definição de bised_lock_pattern:

  enum {
    
     locked_value             = 0,
         unlocked_value           = 1,
         monitor_value            = 2,
         marked_value             = 3,
         biased_lock_pattern      = 5
  };

  Isso parece familiar? Se você não estiver familiarizado, deixe-me adicionar uma observação e olhar novamente:

 enum {
    
      locked_value             = 0,//00 轻量级锁
         unlocked_value           = 1,//01 无锁
         monitor_value            = 2,//10 重量级锁
         marked_value             = 3,//11 GC标记
         biased_lock_pattern      = 5 //101 偏向锁,1位偏向标记和2位状态标记(01)
  };

  Isso mesmo, esta definição é o identificador de status de bloqueio no Mark Word do cabeçalho do objeto.

Resumindo

Insira a descrição da imagem aqui
  Então, por que a máquina virtual adiciona um controle efetivo de atraso padrão ao bloqueio de polarização? A máquina virtual também iniciará alguns threads durante o processo de inicialização e parte da lógica também é controlada internamente. Se o bloqueio de polarização estiver ativado diretamente, geralmente causará a revogação de polarização. A JVM usa muito ao ativar a revogação de polarização . Para ser seguro, não habilitar o bloqueio de polarização no início é mais útil para melhorar a velocidade de inicialização da JVM (parece que isso deveria ser o (╯ □ ╰) o).

Este artigo é baseado no entendimento pessoal do blogueiro. Se houver algum erro, obrigado por apontá-lo!

Acho que você gosta

Origin blog.csdn.net/huangzhilin2015/article/details/115314096
Recomendado
Clasificación