Exemplos de metaprog (Java e Ruby)

Quem desenvolve com Ruby pode até estar acostumado a fazer coisas como utilizar os attr_accessor, attr_writer, etc. que são bons exemplos de metaprog. Mas como é que isso funciona? Vamos ver alguns exemplos em Java e Ruby e mostrar quais são as diferenças entre essas duas linguagens.

class Attrs
  attr_accessor :accessor
  attr_reader :reader
  attr_writer :writer
  attr :attr
end

Esse exemplo mostra os quatro métodos que criam variáveis de instância e métodos para acessar essas variáveis. Lembrando que eles são métodos, ou seja, aquelas linhas de código estão na verdade chamando um método. Esse método, definido dentro da classe Module do Ruby [1], cria uma variável de instância com o nome que você passa como um símbolo, por isso precisamos passar algo da forma “:accessor”, e alguns métodos para oferecer acesso a essa variável de instância utilizando a metaprogramação.

Considerando a classe acima podemos chamar, dentro do escopo dela, qualquer um dos atributos como “@accessor”. Para instâncias dessa classe podemos chamar os métodos “accessor” que retorna o valor daquela variável e “accessor=” que altera o valor da variável.

Podemos então utilizar o seguinte método, que, através de reflexão, recebe um objeto e um atributo, e mostra a acessibilidade do atributo no método.

def get_accessibility(object, attribute)
  puts "Can read? #{object.respond_to?("#{attribute}".to_sym)}"
  puts "Can write? #{object.respond_to?("#{attribute}=".to_sym)}"
end

Esse método utiliza os método “respond_to?” que pode ser chamado em um objeto qualquer, toma como parametro um símbolo e retorna se o objeto tem ou não aquele método. No exemplo estamos construindo o símbolo utilizando o nome do atributo, para o método de leitura apenas precisamos chamar o nome do atributo, para o método de escrita precisamos chamar com um “=” na frente. O resultado da chamada do método nos atributos de um objeto da classe acima mostra a visibilidade dos atributos.

=== Accessor ===
Can read? true
Can write? true
=== Reader ===
Can read? true
Can write? false
=== Writter ===
Can read? false
Can write? true
=== Attribute ===
Can read? true
Can write? false

Vale lembrar que esses métodos são bem diferentes dos modificadores de acesso do Java, pois os modificadores apenas configuram o objeto para não permitir acesso as variáveis. Os métodos attrs do Ruby definem métodos e a variável de instância, e nada lhe impede de fazer qualquer modificação ou escrever métodos de leitura/escrita. No Java também não é tão complicado modificar a acessibilidade dos atributos. Os exemplos a seguir mostram como modificar o acesso de variáveis com Java e Ruby.

Considere a classe java a seguir, com um método privado e uma variável privada.

public class HelloYou {
  private String name;

  public HelloYou(String name){
    this.name = name;
  }

  private String sayHello() {
    return "Hello " + name + "!";
  }
}

O código a seguir mostra como acessar o método privado, e como ler e escrever na classe privada, utilizando a api de reflection do java. Os objetos Method e Field permitem acessar métodos e atributos de uma classe.

import java.util.Scanner;
import java.lang.reflect.*;

public class Main{
  public static void main(String arg[]){
    Scanner scanner = new Scanner(System.in);
    System.out.print("Quem é você? ");
    String name = scanner.nextLine();
    Method privateMethod;
    Field privateField;
    HelloYou hello = new HelloYou(name);
    try {
      privateMethod = hello.getClass().getDeclaredMethod("sayHello");
      privateMethod.setAccessible(true);
      System.out.println(privateMethod.invoke(hello));
      privateField = hello.getClass().getDeclaredField("name");
      privateField.setAccessible(true);
      privateField.set(hello, ((String)privateField.get(hello)).toUpperCase());
      System.out.println(privateMethod.invoke(hello));
    } catch(Exception e) {
      e.printStackTrace();
    }
  }
}

A ideia é pegar um objeto java.lang.reflect.Method e atribuir a ele um dos métodos do objeto que você quer acessar, utilizan o “getClass()” para acessar a classe Class do seu objeto. Uma vez que temos a classe de um objeto, podemos acessar os métodos através do nome do método e os tipos dos parâmetros, bem como os atributos através do nome.

Chamando o método “setAccessible()” nós podemos modificar a visibilidade dos métodos e atributos. Em seguida basta chamar “invoke()” para chamar o método no objeto passado como parâmetro. Para os atributos apenas chamamos “set()” e “get()” de um objeto java.lang.reflect.Field para manipular os valores dos atributos no objeto.

No java, as possibilidades de metaprogramação são bem reduzidas pois não permitem adicionar métodos na classe ou alterar os métodos em tempo de execução. Mas essa é a filosofia da linguagem, reduzir a possibilidade de erros dos programadores através da remoção de poder da linguagem. Mas mesmo assim, alguém com conhecimento na linguagem pode ignorar os modificadores de visibilidade caso seja necessário.

O mesmo exemplo acima em poderia ser algo assim se fosse escrito em Ruby:

class HelloYou
  attr_reader :name

  def initialize(name)
    @name = name
  end

  private
  def say_hello
    "Hello #{@name}"
  end
end

puts "Quem é você?"
name = gets.chomp

hello = HelloYou.new(name)
puts hello.send(:say_hello)
def hello.name=(name)
  @name = name
end
hello.name = name.upcase
puts hello.send(:say_hello)

Para acessar métodos privados, a única coisa que precisamos é chamar o método “send()” e passar o símbolo que representa o método. Já para permitir escrever em um atributo sem um método de escrita, basta definir o método que dá acesso a ele. No exemplo acima, o método foi definido diretamente no objeto, e não na classe.

Ou seja, com um pouco de conhecimento, podemos simplesmente ignorar as regras de visibilidade e acesso de atributos e métodos. Definir um método como privado então serve apenas como documentação do código, ou seja, apenas diz que aquele método não depende de nada fora do objeto e, da mesma forma, não altera nada que esteja fora desse objeto.

Em Ruby a metaprogramação é ainda mais poderosa pois podemos adicionar, modificar, remover, executar, etc. qualquer código em tempo de execução. No entanto esse “poder” exige cuidado para evitar complicações de manutenção de código. Um dos pontos negativos da forte utilização de metaprogramação em Ruby é que, quando se abusa dela, fica muito difícil debugar e manter o código, pois você pode ver no stack trace que ocorreu um erro em um determinado método e, ao procurar por esse método, não encontrar nada.

Na verdade, apesar de ser interessante, dificilmente você vai precisar alterar a visibilidade de métodos e atributos. Geralmente faz mais sentido repensar no design e alterar a visibilidade pelos meios convencionais do que oferecer isso em algum método obscuro. Uma das utilidades é para testar métodos privados, sem entrar na questão de testar ou não métodos privados.

Nos próximos posts vou procurar mais alguns exemplos legais e que fazem mais sentido do que só testar métodos privados. Para conhecer um pouco mais sobre metaprog e reflection em Ruby, vale a pena dar uma olhada no post sobre Reflexão em Ruby [2] e Metaprogramação em Ruby [3].

Referências:

[1] http://www.ruby-doc.org/core-1.9.3/Module.html#method-i-attr
[2] https://brizeno.wordpress.com/2012/03/25/reflexao-em-ruby/
[3] https://brizeno.wordpress.com/2012/03/27/metaprogramacao-em-ruby/

Anúncios

Desenvolvendo jogos com AndEngine!

No post anterior sobre Android eu comentei um pouco sobre como começar a estudar sobre Android, falando um pouco sobre os materiais que tive contato e no final comentei um pouco sobre as Engines, que facilitam a vida do desenvolvedor. Uma que citei foi a AndEngine (http://www.andengine.org/), que é um projeto Open Source de uma engine para jogos.

Então neste post vou mostrar uma introdução ao desenvolvimento com a AndEngine, para isso vamos implementar o exemplo clássico inicial: Hello World!

Criando o projeto:

Para começar do começo vamos criar um novo projeto Android no eclipse. Com o projeto no workspace crie uma nova pasta chamada lib, na raiz do projeto. Nela vamos colocar o .jar da AndEngine. Como a AndEngine é um projeto open source, é possível baixar os códigos e linkar ao seu projeto (http://wiki.andengine.org/Getting_And_Updating_AndEngine), no entanto, vamos utilizar agora o arquivo .jar da engine, que fica bem mais fácil de linkar ao projeto. Baixe o arquivo aqui.

Baixou o arquivo e criou a pasta lib? Agora é só colar o arquivo dentro da pasta. Agora no eclipse vá até a pasta lib do seu workspace e clique com o botão direito do mouse, depois clique em Build Path e Configure Build Path. Na tela que vai aparecer clique na aba Order and Export e selecione o AndEngine.jar. Pronto, agora já estamos com a Andengine linkada ao nosso projeto.

Uma Actvity diferente

Agora vamos ver um pouco de código. Uma classe padrão já é criada junto com o projeto, no entanto ela deriva da classe Activity da API do android. Para utilizar a AndEngine precisamos criar uma classe que derive de BaseGameActivity. O método onCreate() já não é mais necessário, então delete ele.

Provavelmente um erro será apontado na classe, como derivamos de BaseGameActivity, precisamos implementar alguns métodos, então clique no indicador de erro do lado esquerdo da linha e selecione “Add unimplemented methods”, para que o eclipse gere todos estes métodos para você. Sua classe deve estar assim:

public class TutorialAndengineActivity extends BaseGameActivity {

	@Override
	public void onLoadComplete() {
		// TODO Auto-generated method stub

	}

	@Override
	public Engine onLoadEngine() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void onLoadResources() {
		// TODO Auto-generated method stub

	}

	@Override
	public Scene onLoadScene() {
		// TODO Auto-generated method stub
		return null;
	}

}

Estes métodos indicam o ciclo de vida de um app que utilize a AndEngine. Para entermos melhor, faça o seguinte: dentro da classe crie uma String constante chamada TAG:

public class TutorialAndengineActivity extends BaseGameActivity {
	// Essa string vai ser utilizada para filtrar o LogCat
	public static final String TAG = "AndEngineTest";
	...
}

Agora, dentro de cada um destes métodos coloque a seguinte chamada:

	public void onLoadComplete() {
		Log.i(TAG, "onLoadComplete()");
	}

Fazendo o app rodar

Agora é possível ver no LogCat o que exatamente está acontecendo. Beleza, então vamos fazer o aplicativo rodar. O método onLoadEngine() deve retornar um objeto Engine, esse objeto tem as configurações que seu aplicativo vai precisar. Vamos contruí-lo então:

	@Override
	public Engine onLoadEngine() {
		// Aqui é preciso configurar um objeto Engine com as configurações do
		// seu app. Este método é chamado primeiro
		Log.i(TAG, "onLoadEngine()");

		Display displayPadrao = getWindowManager().getDefaultDisplay();
		// Declare estas variáveis como atributos int da classe
		cameraWidth = displayPadrao.getWidth();
		cameraHeight = displayPadrao.getHeight();
		Log.i(TAG, "cameraWidth: " + cameraWidth + " cameraHeight: "
				+ cameraHeight);

		// Esse cara faz com que o app funcione direito em qualquer resolução
		RatioResolutionPolicy resolucao = new RatioResolutionPolicy(
				cameraWidth, cameraHeight);

		Camera camera = new Camera(0, 0, cameraWidth, cameraHeight);

		EngineOptions configuracoesEngine = new EngineOptions(true,
				ScreenOrientation.LANDSCAPE, resolucao, camera);

		return new Engine(configuracoesEngine);
	}

Não se assuste com o código, vamos por parte. Primeiro precisamos de um objeto display que contenha as informações do display do celular que ta rodando o app. Depois disso nos pegamos o valor de largura e altura deste display. Agora vem um objeto que configurar a resolução do app, ele recebe o tamanho e depois se vira pra exibir as imagens direitinho. Depois precisamos criar uma câmera, que é a área que vai exibir alguma coisa na tela. Agora vamos criar um objeto que vai ter as configurações da engine, o primeiro parametro dele é se o app deve ser fullscreen ou não, depois é preciso indicar qual a orientação da tela, LANDSCAPE é deitado e PORTRAIR é em pé. Por fim passamos o cara que controla a resolução e a câmera. Agora basta criar uma nova engine com as configurações selecionadas e retornar ela.

Mas calma, ainda não execute o projeto, antes é preciso implementar o método onLoadScene. Nele é preciso carregar a cena do jogo, que é uma camada onde as imagens e textos vão ser desenhados. Por enquanto basta fazer isso:

	public Scene onLoadScene() {
		// Esse método carrega a cena do jogo, ou seja, a camada onde tudo vai
		// ser desenhado
		Log.i(TAG, "onLoadScene()");

		return new Scene();
	}

Pronto agora sim, pode rodar tranquilo. Só que não vai aparecer nada. Para adicionar uma cor na tela altere o onLoadScene para:

	public Scene onLoadScene() {
		// Esse método carrega a cena do jogo, ou seja, a camada onde tudo vai
		// ser desenhado
		Log.i(TAG, "onLoadScene()");

		Scene cenaPrincipal = new Scene();
		cenaPrincipal.setBackground(new ColorBackground(0.1f, 0.3f, 0.8f));

		return cenaPrincipal;
	}

Pronto, agora sim, se tiver dado tudo certo, deve aparecer uma tela azul (BSOD), mas não, seu Android não travou.

Até que enfim o Hello World!

Beleza, agora que o bicho tá rodando, vamos implementar o clássico hello world! Crie dois atributos da classe que vão ser necessário para escrever na tela:

	private BitmapTextureAtlas fontTexture;
	private Font font;

Esse BitmapTextureAtlas é um bitmap bem grande que vai guardar várias imagens dentro dele, no caso vamos guardar a fonte. A Font é uma classe que guarda as informações básicas das fontes. Vamos instanciá-las e tudo ficará mais claro. Dentro do método onLoadResources adicione o seguinte código:

	@Override
	public void onLoadResources() {
		// Aqui você vai carregar os recursos que seu app vai precisar, como
		// imagens, fontes sons e etc.
		Log.i(TAG, "onLoadResources()");

		fontTexture = new BitmapTextureAtlas(256, 256,
				TextureOptions.BILINEAR_PREMULTIPLYALPHA);
		font = new Font(fontTexture, Typeface.create(Typeface.DEFAULT,
				Typeface.BOLD), 40, true, Color.BLACK);
		// O atributo mEngine é a engine que você configurou no método
		// onLoanEngine(), que é herdado do BaseGameActivity
		mEngine.getTextureManager().loadTexture(fontTexture);
		mEngine.getFontManager().loadFont(font);
	}

Ao instanciar o fontTexture é preciso tomar cuidado ao escolher o tamanho, pois ele precisa ser uma potência de dois (não me pergunte porque). Em seguida precisamos configurar a fonte. O primeiro argumento é a textura onde a fonte vai ser desenhada. Depois precisamos criar um objeto TypeFace, que guarda a família da fonte e os detalhes de estilo, no exemplo utilizamos a fonte padrão e em negrito. Depois precisamos indicar o tamanho da fonte e se ele vai utilizar AntiAlias. No fim indicamos a cor.

Beleza, agora que configuramos a fonte é preciso fazer com que o app conheça ela, para isto utilizamos o atributo mEngine, que é a engine que acabamos de criar no método onLoadEngine. Para apresentar uma textura, utilizamos o getTextureManager, e para apresentar a fonte utilizamos o…? Correto, getfontManager.

Pronto, agora configuramos os nossos recursos. Vamos então partir para a exibição das informações de fato. Para isto, vamos alterar o onLoadScene(). Nele criamos uma cena e adicionamos uma cor de background, agora vamos criar um objeto Text e anexar ele a cena:

	@Override
	public Scene onLoadScene() {
		// Esse método carrega a cena do jogo, ou seja, a camada onde tudo vai
		// ser desenhado
		Log.i(TAG, "onLoadScene()");

		Scene cenaPrincipal = new Scene();
		cenaPrincipal.setBackground(new ColorBackground(0.1f, 0.3f, 0.8f));

		String helloWorld = "Hello World!\n" + getString(R.string.app_name);
		Text texto = new Text(0, 0, font, helloWorld);

		cenaPrincipal.attachChild(texto);
		return cenaPrincipal;
	}

O objeto Texto recebe uma posição para ser desenhado, uma fonte e uma string que será exibida. Depois disso utilizamos o método attachChild para anexar o texto a cena. Se rodar o projeto agora verá que será exibida a mensagem Hello World! e o nome do projeto que você criou.

Um pouco além do Hello World

Ótimo, conseguimos o Hello World. Mas e que tal exibir uma imagem na tela? O processo é semelhante a exibição do texto. Precisamos de um atlas de bitmap novo, já que o outro foi utilizado para guardar a fonte, e de uma textura para carregar a imagem. Adicione os seguintes atributos na classe:

	private BitmapTextureAtlas bitmapTextureAtlas;
	private TextureRegion texturaImagem;

Agora vamos instanciá-los. Você já deve saber em qual método vamos fazer isso né? Exatamento, no onLoadResources()

	@Override
	public void onLoadResources() {
		...
		bitmapTextureAtlas = new BitmapTextureAtlas(128, 128,
				TextureOptions.BILINEAR_PREMULTIPLYALPHA);
		BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");
		texturaImagem = BitmapTextureAtlasTextureRegionFactory.createFromAsset(
				bitmapTextureAtlas, this, "icon.png", 0, 0);
		mEngine.getTextureManager().loadTexture(bitmapTextureAtlas);

	}

Agora vem mais um detalhe importante. As imagens são carregadas no android pelas pastas dentro da pasta “res/drawable” certo? Ao utilizar a AndEngine é preciso utilizar a pasta “assets/”. Então copie o ícone do Andriod que fica dentro da pasta “res/drawable” para a pasta “assets/gfx”, se ela não existir crie.

Aquele BitmapTextureAtlasTextureRegionFactory é uma classe que contém métodos estáticos para carregar as texturas. Primeiro precisamos dizer que o caminho básico é o “gfx/” assim ele vai saber encontrar a imagem que acabamos de copiar. Agora vamos atribuir para o objeto texturaImagem a imagem do ícone, utilizando o método createFromAsset. Nele precisamos indicar um atlas de bitmap, um contexto (que é a própria classe que estamos implementando), o nome do arquivo e a posição onde ele vai ser guardado. Lembra que o atlas é um bitmap gigante? Então, precisamos indicar em qual posição, dentro deste bitmap, vai ser guardada a imagem. Por isso aquele 0,0 no final.

Por fim, vamos dizer que o que acabamos de criar existe para o aplicativo, conforme fizemos com a fonte. Agora que os recursos foram carregados, basta desenhar o sprite na tela. Para isto vamos voltar ao método onLoadScene:

	@Override
	public Scene onLoadScene() {
		...
		int imagemX = cameraWidth / 2 - texturaImagem.getWidth() / 2;
		int imagemY = cameraHeight / 2 - texturaImagem.getHeight() / 2;
		Sprite imagem = new Sprite(imagemX, imagemY, texturaImagem);

		cenaPrincipal.attachChild(imagem);
		cenaPrincipal.attachChild(texto);
		return cenaPrincipal;
	}

Um Sprite é uma textura que possui um aposição no eixo xy. Para isto precisamos indicar qual a posição do sprite e qual a sua textura. Feito isto, basta anexar o sprite na cena principal. Pronto! Rode o aplicativo e se delicie com a maravilha que você acabou de criar! 😀

Próximos passos

Se você chegou até aqui, parabéns, é sinal de que quer realmente aprender a utilizar a AndEngine, ou então só saiu rolando pra baixo esse monte de texto. Se você quiser um exemplo mais prático de jogo mesmo, eu recomendo esse link: https://jimmaru.wordpress.com/2011/09/28/andengine-simple-android-game-tutorial/. Aqui o cara mostra como fazer um jogo mesmo, com interações, músicas e tudo mais. Eu só não gostei muito porque o código ficou bem gambiarroso, principalmente no finalzinho, e ele fez tudo numa classe só, mas enfim, dá pra ver como fazer bastante coisa com a AndEngine.

Agora que você já começou a desenvolver jogos para Android, é só ficar milionário e curtir a vida 😀

Código fonte

Pra quem quiser baixar o projeto completo e só rodar no eclipse, tá aqui o link pro Github: https://github.com/MarcosX/AndEngine-Tutorial. O código tá todo comentado, então deve dar pra entender o que cada parte faz. Só não esqueça de configurar o Build Path com a AndEngine.jar!

Android Nv. 1 – Aprendiz

Este post tem como objetivo fazer uma pequena introdução e prover algumas referência para quem quiser iniciar no desenvolvimento mobile na plataforma Android.

O que é Android

Para iniciar nada como dar uma olhada no site: http://www.android.com/. Aqui é possível ver as novidades da plataforma e conhecer um pouco sobre seu ecossistema.

Para nós, desenvolvedores, o legal mesmo é ver a parte dos developers! Então vejam o site: http://developer.android.com. Aqui podemos ver informações da SDK (Software Development Kit) do Android, anúncios de eventos, videos com palestras, guia para iniciantes, referência, entre várias outras informações. Vale a pena fuçar o site todo 😀

Links sobre como instalar a SDK tem aos montes na internet, e no site dos desenvolvedores de Android também tem um excelente tutorial, em inglês. Caso ainda tenha dificuldades na língua basta googlar por aí que será bem fácil achar uma maneira de instalar o SDK no Eclipse.

Bom, após essa parte inicial de instalação é legal ver alguns exemplos práticos, pra ver alguma coisa rodando né? O grande amigo meu blogou sobre alguns tutoriais legais sobre o Android: http://yuriadamsmaia.wordpress.com.

Antes de sair por aí copiando código de tutorial, baixando exemplo do Git, vale a pena perder algum tempo vendo como o Android organiza o seu projeto, assim você terá uma entendido maior sobre a plataforma. Por isso, vale a pena ver este post: http://yuriadamsmaia.wordpress.com/2011/03/24/desenvolver-para-android-entendendo-o-helloworld-i/.

Agora sim, procure por tutoriais de Android, veja exemplos, aprenda sobre a organização MVC do Android, só da pra aprender sobre código escrevendo código né. Se você tem algum recurso guardado eu aconselho muito conferir o livro Google Android do autor Ricardo R. Lecheta, pela editora Novatec.

O livro tem uma abordagem bem prática, desde o começo você vê os conceitos com códigos, exemplos práticos de utilização. Até mesmo pra quem já conhece sobre a plataforma vai aproveitar bem o livro, porque ele cobre muito conteúdo.

O único problema é que a versão dele já está ficando meio desatualizada, a plataforma já vai pra sua versão 4.0. Mas como a maioria dos aparelhos ainda roda nas versões 2.2 e 2.3 o livro vai muito bem.

Se você tá com a grana meio curta, outro excelente opção é a apostila do Luciano Alves: http://apostilaandroid.ueuo.com/inicio.php. Ela é disponibilizada para download gratuitamente no site.

O conteúdo da apostila também é extremamente prático e dão uma excelente visão sobre os componentes gráficos da plataforma, sempre com exemplos de código. O destaque da apostila fica para a explicação bem detalhada do uso de arquivos XML para definição de formulários e telas dos aplicativos.

Bom, com isso já dá pra ter um bom norte pra começar com o Android. Quando estiver dominando o conteúdo e se sentindo confortável com  o desenvolvimento Android procure por engines que facilitem o trabalho no desenvolvimento. Quem curte jogos pode procurar pelo projeto Andengine http://www.andengine.org/ uma engine 2D para jogos gratuita!

E fiquem de olho aqui no blog também, em breve teremos alguns post sobre desenvolvimento Android. Obrigado pela visita e bons estudos!

Praticando concorrência em Java! – Semáforos

Como falado no post anterior sobre concorrência em java, o problema do Produtor/Consumidor pode ser resolvido utilizando um monitor que bloqueia o recurso, permitindo apenas um acesso de cada vez.

Desta vez vamos comentar um pouco sobre semáforos, que permitem um número maior de Thread acessando os recursos.

Semáforos

Um semáforo é uma estrutura de dados que controle o acesso de aplicações aos recursos, baseando-se em um número inteiro, que representa a quantidade de acessos que podem ser feitos. Assim utilizamos semáforos para controlar a quantidade de acesso a determinado recurso.

Na API do Java existe uma implementação de semáforos que fazem justamente esse controle. Vamos ver a seguir um exemplo que usa o Semáforo nativo do Java.

Utilizando semáforos

Primeiro vamos definir uma implementação de Thread que vai utilizar o semáforo.

public class ProcessadorThread extends Thread {
	private int idThread;
	private Semaphore semaforo;

	public ProcessadorThread(int id, Semaphore semaphore) {
		this.idThread = id;
		this.semaforo = semaphore;
	}
}

Definimos inicialmente um identificador para a nossa Thread e uma referência a um semáforo que irá controlar o acesso a essas variáveis.

Agora vamos definir os métodos da nossa Thread, dentro da classe ProcessadorThread:

	private void processar() {
		try {
			System.out.println("Thread #" + idThread + " processando");
			Thread.sleep((long) (Math.random() * 10000));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

Este método processar() apenas faz a thread dormir por algum tempo, simulando o efeito de um processamento longo.

	private void entrarRegiaoNaoCritica() {
		System.out.println("Thread #" + idThread + " em região não crítica");
		processar();
	}

Este método simula o acesso da Thread em uma região não crítica, ou seja, uma região ao qual não é necessário pedir uma trava. Exibimos o atual estado da Thread, para facilitar o entendimento do progama, e realizamos um processamento qualquer.

	private void entrarRegiaoCritica() {
		System.out.println("Thread #" + idThread
				+ " entrando em região crítica");
		processar();
		System.out.println("Thread #" + idThread + " saindo da região crítica");
	}

Este outro método será utilizado para simular o acesso da Thread em uma região crítica. Ele será chamado logo após conseguir a trava do semáforo.

	public void run() {
		entrarRegiaoNaoCritica();
		try {
			semaforo.acquire();
			entrarRegiaoCritica();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			semaforo.release();
		}
	}

E finalmente, como nossa classe extende o comportamento de uma Thread, nós sobrecarregamos o método run() que será chamado quando a Thread iniciar. Neste método nós realizamos um processamento não crítico, depois requisitamos o acesso ao semáforo (com o semaforo.acquire()) e em seguida realizamos o processamento de uma região crítica. Por fim, liberamos o recurso do semáforo (com o semaforo.release()).

Entendendo um pouco mais sobre semáforos

Vamos agora falar um pouco de teoria sobre semáforos. Todo semáforo deve possuir dois métodos: P e V, que têm sua origem das palavras parsen (passar) e e vrygeren (liberar). Esta definição de semáforo foi proposta por Dijkstra para evitar o tão temido DeadLock.

Quando se quer requisitar o recurso, faz-se uma chamada ao método P, que verifica se é possível liberar o recurso. Ao terminar, faz-se uma chamada ao método V, que notifica as outras Thread que o recurso foi liberado.

Na implementação do Java, o método “acquire()” faz o papel do método P e o método “release()” faz o papel do método V. Vamos analisar o método main e ver como são utilizados os semáforos:

	public static void main(String[] args) {
		int numeroDePermicoes = 2;
		int numeroDeProcessos = 6;
		Semaphore semaphore = new Semaphore(numeroDePermicoes);
		ProcessadorThread[] processos = new ProcessadorThread[numeroDeProcessos];
		for (int i = 0; i < numeroDeProcessos; i++) {
			processos[i] = new ProcessadorThread(i, semaphore);
			processos[i].start();
		}
	}

Para construir um semáforo precisamos informar o número máximo de Thread que podem acessar o recurso ao mesmo tempo. No nosso exemplo, apenas duas Thread poderão entrar na região crítica. Executando o programa a saída no console será algo do tipo:

Thread #1 em região não crítica
Thread #1 processando
Thread #0 em região não crítica
Thread #0 processando
Thread #5 em região não crítica
Thread #5 processando
Thread #3 em região não crítica
Thread #3 processando
Thread #2 em região não crítica
Thread #2 processando
Thread #4 em região não crítica
Thread #4 processando
Thread #0 entrando em região crítica
Thread #0 processando
Thread #4 entrando em região crítica
Thread #4 processando
Thread #4 saindo da região crítica
Thread #5 entrando em região crítica
Thread #5 processando
Thread #5 saindo da região crítica
Thread #3 entrando em região crítica
Thread #3 processando
Thread #0 saindo da região crítica
Thread #1 entrando em região crítica
Thread #1 processando
Thread #1 saindo da região crítica
Thread #2 entrando em região crítica
Thread #2 processando
Thread #3 saindo da região crítica
Thread #2 saindo da região crítica

Como já comentamos, no Java os Thread são acordados aleatoriamente, então a saída não será a mesma. O que é realmente importante notar é que nunca temos mais que duas Thread na região crítica.

A Thread 0 e 4 entram na área crítica e, somente quando a Thread 4 libera o recurso, a Thread 5 entra na região.

No próximo post vamos ver como implementar um semáforo próprio para resolver o problema do Produtor/Consumidor.

Obrigado pela visita, espero que este post tenha ajudado. Se gostou do post compartilhe com seus amigos e colegas, senão, comente o que pode ser melhorado. Encontrou algum erro no código? Comente também. Possui alguma outra opinião ou alguma informação adicional? Comenta ai! 🙂

Referências:

[1] JENKOV, Jakob. Semaphore. Disponível em: http://tutorials.jenkov.com/java-concurrency/semaphores.html. Acesso em: 25 set. 2011.
[2] LIMA J., José; FREITAS, Veronice de. Semáforos. Disponível em: http://www.jr.eti.br/mestrado/cmp041/semaforos.html. Acesso em: 25 set. 2011.

Praticando concorrência em Java!

Neste post vamos mostrar um exemplo prático de programação com concorrência em Java explorando as ferramentas da linguagem.

E no começo haviam os monitores

Para começar vamos falar sobre uma estrutura básica na programação concorrente: o monitor.

Segundo [1] monitor é uma técnica utilizada para sincronizar tarefas que compartilham um recurso. ou seja, o monitor oferece uma interface para permitir a manipulação de um recurso compartilhado. Para tanto utiliza uma trava de exclusão mútua, que consiste de variáveis de controle e regras para liberar ou travar o recurso.

De maneira prática, o monitor basicamente é uma classe que controla o recurso, assim quando for preciso requisitá-lo devemos enviar o pedido para ela.

Produtor/Consumidor

Para exemplificar vamos analisar o problema do Produtor e Consumidor. Segundo [2]:

Uma ou mais thread de produtores criam um produto e colocam em um buffer. Uma ou mais thread de consumidores consomem o produto colocado no buffer. O produtor precisa esperar o buffer ficar livre para produzir o produto e o cliente precisa esperar o buffer ficar preenchido para consumir o produto.

A tarefa do problema é sincronizar o acesso ao recurso, no caso a pilha, para que produtores saibam quando podem produzir e consumidores saibam quando podem consumir. Vamos então para a parte prática!

Primeiro vamos criar a classe do Consumidor:

public class Consumidor extends Thread {
	private int idConsumidor;
	private Buffer pilha;
	private int totalConsumir;

	public Consumidor(int id, Buffer p, int totalConsumir) {
		idConsumidor = id;
		pilha = p;
		this.totalConsumir = totalConsumir;
	}

	public void run() {
		for (int i = 0; i < totalConsumir; i++) {
			pilha.get(idConsumidor);
		}
		System.out.println("Consumidor #" + idConsumidor + " concluido!");
	}
}

Essa classe é derivada da clase Thread, ou seja, cada cliente vai funcionar em um thread diferente. Os dados que utilizamos são um identificador (idConsumidor), uma referência para um Buffer e um contador (totalConsumir) que vai indicar quanto deve ser consumido pelo consumidor.

O método run() é chamado quando a thread for iniciada, ou seja, é nele que devemos definir o nosso cliente de fato. Definimos então o laço para executar as chamadas que consomem o recurso do buffer.

Vamos então definir a classe Produtor:

public class Produtor extends Thread {
	private int idProdutor;
	private Buffer pilha;
	private int producaoTotal;

	public Produtor(int id, Buffer p, int producaoTotal) {
		idProdutor = id;
		pilha = p;
		this.producaoTotal = producaoTotal;
	}

	public void run() {
		for (int i = 0; i < producaoTotal; i++) {
			pilha.set(idProdutor, i);
		}
		System.out.println("Produtor #" + idProdutor + " concluido!");
	}
}

De maneira semelhante ao Consumidor, o produtor possui um identificador, uma referência para um buffer e um total de produtos a serem produzidos. Note que essa classe também é uma Thread, ou seja, cada produtor será executado independentemente. O método run() também é bem semelhante ao do Consumidor, um laço que faz as chamadas ao buffer.

Sincronizando o acesso ao recurso compartilhado

Agora vem a parte principal, o buffer. Ele possui um conteúdo, que é colocado pelo produtor, e um booleano que indica quando o conteúdo está disponível.

Para permitir que um produtor coloque um produto ela oferece um método set, que carrega o conteúdo e avisa para as outras thread que o produto está disponível. Para dar acesso ao Consumidor, o buffer oferece um método get, que devolve o conteúdo e avisa para outras thread que o produto não está mais disponível.

Esta classe merece uma atenção especial e será detalhada em partes menores. Primeiro veremos o método set():

	public synchronized void set(int idProdutor, int valor) {
		while (disponivel == true) {
			try {
				System.out.println("Produtor #" + idProdutor + " esperando...");
				wait();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		conteudo = valor;
		System.out.println("Produtor #" + idProdutor + " colocou " + conteudo);
		disponivel = true;
		notifyAll();
	}

Enquanto houver um conteúdo disponível no buffer, o produtor deve esperar. Quando o buffer não estiver mais com conteúdo disponível, o conteúdo é carregado e as outras thread são notificadas que um novo conteúdo está disponível.

	public synchronized int get(int idConsumidor) {
		while (disponivel == false) {
			try {
				System.out.println("Consumidor #" + idConsumidor
						+ " esperado...");
				wait();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		System.out.println("Consumidor #" + idConsumidor + " consumiu: "
				+ conteudo);
		disponivel = false;
		notifyAll();
		return conteudo;
	}

De forma semelhante ao Produtor, no método get o consumidor deve esperar enquanto não houver conteúdo disponível. Quando o conteúdo estiver disponível novamente o consumidor consome o recurso e notifca as outras thread que não há mais recurso disponível.

O código completo da classe Buffer fica assim:

package br.concorrencia.produtorConsumidor;

public class Buffer {

	private int conteudo;
	private boolean disponivel;

	public synchronized void set(int idProdutor, int valor) {
		while (disponivel == true) {
			try {
				System.out.println("Produtor #" + idProdutor + " esperando...");
				wait();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		conteudo = valor;
		System.out.println("Produtor #" + idProdutor + " colocou " + conteudo);
		disponivel = true;
		notifyAll();
	}

	public synchronized int get(int idConsumidor) {
		while (disponivel == false) {
			try {
				System.out.println("Consumidor #" + idConsumidor
						+ " esperado...");
				wait();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		System.out.println("Consumidor #" + idConsumidor + " consumiu: "
				+ conteudo);
		disponivel = false;
		notifyAll();
		return conteudo;
	}
}

O importante ai é verificar que os métodos get e set do buffer possuem um modificador especial: synchronized.

Segundo [4], métodos sincronizados são uma estratégia simples para prevenir erros de interferência e inconsistência de memória. Se um objeto é acessado por mais de uma thread (o que no nosso exemplo é o objeto Buffer), todas as operações de escrita e leitura neste objeto devem ser feitas através de métodos sincronizados.

Para testar o nosso código, vamos criar o seguinte método main:

	public static void main(String[] args) {
		Buffer bufferCompartilhado = new Buffer();
		Produtor produtor1 = new Produtor(1, bufferCompartilhado, 5);
		Produtor produtor2 = new Produtor(2, bufferCompartilhado, 5);
		Consumidor consumidor1 = new Consumidor(1, bufferCompartilhado, 2);
		Consumidor consumidor2 = new Consumidor(2, bufferCompartilhado, 8);

		produtor1.start();
		consumidor1.start();
		produtor2.start();
		consumidor2.start();
	}

Criamos dois produtores e dois consumidores. Em seguida executamos o método da classe Thread chamado start(). Este método vai então inicializar a Thread e logo em seguida vai executar o método run(), que nós definimos nas classes Consumidor e Produtor.

Observando a saída no console, temos algo do tipo:

Produtor #1 colocou 0
Produtor #1 esperando…
Consumidor #1 consumiu: 0
Consumidor #1 esperado…
Produtor #1 colocou 1
Produtor #1 concluido!
Consumidor #1 consumiu: 1
Consumidor #1 esperado…
Produtor #2 colocou 0
Produtor #2 esperando…
Consumidor #2 consumiu: 0
Consumidor #2 concluido!
Produtor #2 colocou 1
Produtor #2 concluido!
Consumidor #1 consumiu: 1
Consumidor #1 concluido!

A ordem de execução pode mudar pois a chamada aos Thread são feitas aleatoriamente em Java. Quando o método wait() na classe Buffer é executado, a Thread que está acessando ele fica em estado de espera. Quando o método notifyAll() é chamado, TODAS as Thread que estão em espera são acordadas e executadas, por isso definimos um laço while nos métodos get e set, ou seja, a Thread só será liberada quando a condição for verdadeira.

Uma discussão mais aprofundada sobre o assunto pode ser encontrada em [4]. No próximo post vamos ver alguns exemplos mais legais usando semáforos de diversos tipos para controlar o acesso ao recurso compartilhado.

Obrigado pela visita, espero que este post tenha ajudado. Se gostou do post compartilhe com seus amigos e colegas, senão, comente o que pode ser melhorado. Encontrou algum erro no código? Comente também. Possui alguma outra opinião ou alguma informação adicional? Comenta ai! 🙂

Referências:

[1] WIKIPEDIA. Monitor (concorrência). Disponível em: http://pt.wikipedia.org/wiki/Monitor_(concorrência). Acesso em: 23 set. 2011.
[2] MARTIN, Robert C. Clean code: a handbook of agile software craftsmanship.
[3] Sincronização de Threads. Disponível em: http://www.dsc.ufcg.edu.br/~jacques/cursos/map/html/threads/sincronizacao.html. Acesso em 23 set. 2011.
[4] ORACLE. Synchronized Methods. Disponível em: http://download.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html. Acesso em 23 set. 2011.