Disponibilizando ConcurrencyLock

0 respostas
P

Ola galera, sou novo por aqui.

Estou disponibilizando este meu trabalho, se trata de uma trava como o sync e entre outros nativos. O que diferencia dos outros é que este pode ser utilizado com Prioridades. Pra quem trabalha com Multi-Threading, isso é uma mão na massa.

Segue o código:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * Concurrency Lock
 * 
 *         Copyright 2014 Pedro H. Chaves
 * 
 *         Licensed under the Apache License, Version 2.0 (the "License"); you
 *         may not use this file except in compliance with the License. You may
 *         obtain a copy of the License at
 * 
 *         http://www.apache.org/licenses/LICENSE-2.0
 * 
 *         Unless required by applicable law or agreed to in writing, software
 *         distributed under the License is distributed on an "AS IS" BASIS,
 *         WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 *         implied. See the License for the specific language governing
 *         permissions and limitations under the License.
 */
final public class ConcurrencyLock {
	
	// Final Private Variables
	final private AtomicBoolean mAwait = new AtomicBoolean(false);
	final private List<Identify> mIdentifications = new ArrayList<Identify>();
	
	// Private Variables
	private int mLockCount;
	private volatile Thread mIdentify = Thread.currentThread();
	private volatile boolean mIdenityLocked = false;
	private volatile boolean mInterruptible = true;
	
	/**
	 * Set Interruptible
	 * 
	 * @param interruptible
	 */
	final public void setInterruptible(final boolean interruptible) {
		mInterruptible = interruptible;
	}
	
	/**
	 * Try Acquire Lock
	 * <p>
	 * 
	 * @param priority
	 *            Greater than 0
	 * @param dellayInMillis
	 *            Dellay in Millis
	 * @return True if was successfully acquired
	 */
	final public boolean tryAcquire(final int priority, final int dellayInMillis) {
		identify(priority);
		int result = performAcquire(dellayInMillis);
		disidentify();
		if (result > 0)
			acquirePerformed();
		return result == 2;
	}
	
	/**
	 * Try Acquire Lock
	 * <p>
	 * 
	 * @param priority
	 *            Greater than 0
	 * @return True if was successfully acquired
	 */
	final public boolean tryAcquire(final int priority) {
		return tryAcquire(priority, -1);
	}
	
	/**
	 * Try Acquire Lock
	 * <p>
	 * 
	 * @return True if was successfully acquired
	 */
	final public boolean tryAcquire() {
		return tryAcquire(0);
	}
	
	/**
	 * Increments acquire
	 */
	final public void acquire() {
		if (Thread.currentThread() != mIdentify)
			throw new RuntimeException("Was not possible to acquire another lock because it was not previously locked.");
		mLockCount++;
	}
	
	/**
	 * Release Lock
	 */
	final public void release() {
		if (mIdentify != Thread.currentThread()) {
			throw new RuntimeException("Unable to release the lock, because it was not previously captured.");
		} else {
			if (--mLockCount == 0)
				mIdenityLocked = false;
		}
	}
	
	/**
	 * Return true if was interrupted
	 * 
	 * @return
	 */
	final private boolean isInterrupted() {
		return Thread.currentThread().isInterrupted() && mInterruptible;
	}
	
	/**
	 * Identify a lock
	 * 
	 * @param priority
	 */
	final private void identify(final int priority) {
		synchronized (ConcurrencyLock.this) {
			mIdentifications.add(new Identify(Thread.currentThread(), priority));
			Collections.sort(mIdentifications, mComparator);
		}
	}
	
	/**
	 * Disidentify a lock
	 */
	final private void disidentify() {
		synchronized (ConcurrencyLock.this) {
			final Iterator<Identify> itr = mIdentifications.iterator();
			while (itr.hasNext()) {
				final Identify identify = itr.next();
				if (identify.mIdentify == Thread.currentThread())
					itr.remove();
			}
		}
	}
	
	/**
	 * Wait for the top priority and block.
	 */
	final private int performAcquire(final long delayInMillis) {
		final long startedTime = System.currentTimeMillis();
		while (true) {
			synchronized (ConcurrencyLock.this) {
				if (mIdentifications.get(0).mIdentify == Thread.currentThread()) {
					if (!mAwait.getAndSet(true))
						break;
				}
			}
			if (isInterrupted() || (delayInMillis >= 0 && (System.currentTimeMillis() - startedTime) > delayInMillis))
				return 0;
		}
		while (mIdenityLocked) {
			if (isInterrupted() || (delayInMillis >= 0 && (System.currentTimeMillis() - startedTime) > delayInMillis))
				return 1;
			else if (mInterruptible && (mIdentify.isInterrupted() || !mIdentify.isAlive()))
				break;
		}
		mIdenityLocked = true;
		mIdentify = Thread.currentThread();
		mLockCount = 1;
		return 2;
	}
	
	/**
	 * Unblock queue.
	 */
	final private void acquirePerformed() {
		mAwait.set(false);
	}
	
	/**
	 * Lock Identify
	 */
	final private class Identify {
		
		// Final Private Variables
		final Thread mIdentify;
		final int mPriority;
		
		/**
		 * Constructor
		 * 
		 * @param identify
		 * @param priority
		 */
		private Identify(final Thread identify, final int priority) {
			mIdentify = identify;
			mPriority = priority;
		}
	}
	
	/**
	 * Comparator
	 */
	final private Comparator<Identify> mComparator = new Comparator<Identify>() {
		
		/**
		 * Comparator
		 * 
		 * @param o1
		 * @param o2
		 * @return
		 */
		@Override
		public int compare(Identify o1, Identify o2) {
			return o2.mPriority - o1.mPriority;
		}
	};
}

Para usar é muito simples, segue um exemplo abaixo com a utilização do ConcurrencyLock(). No exemplo é mostrado 5 threads trabalhando juntas e a trava é utilizada para criar uma operação sincronizada entres elas. E a operação utilizada no exemplo se trata de uma simples operação Matemática, onde cada Thread faz uma operação em uma variável global. No total são realizadas 100000 operações nesta variável, o resultado nunca sera o mesmo. Mas dependendo da prioridade de cada trava, uma mesma Thread pode realizar mais vezes sua operação e outras realizarem menas vezes sua operação.

Para estabelecer uma trava é utilizado "tryAcquire(prioridade)" e para liberar esta trava é utilizado "release()". Caso necessário e você queira incrementar uma trava em uma mesma Thread apos utilizar "tryAcquire(prioridade)" é utilizado "acquire()", mas neste caso o "release()" terá de ser chamado mais de uma vez, uma para liberar o "acquire()" e outra para liberar o "tryAcquire()".
O "tryAcquire(prioridade)" retorna "true" ou "false" dependendo de seu sucesso. Uma tentativa de trava só pode falhar quando a Thread foi interrompida ou então quando é utilizado "tryAcquire(prioridade, tempoEmMillis)" e o tempo foi excedido. Quando uma trava é adquirida em uma Thread, esta trava sera liberada automaticamente caso esta Thread seja interrompida ou então termine seu processo sem liberar a trava. Para desativar este método utilize "setInterruptible(false)", porem isso pode acarretar em um DeadLock.

Como dito, segue o exemplo que realiza varias operações Matemáticas. Se olharem bem a Thread 5 utiliza o "tryAcquire(4)" com uma prioridade de "4", já a Thread 4 tem uma prioridade de "3". Isso diz que a Thread 5 sera liberada mais vezes e realizara a maior quantidade de operações Matemáticas do total de operações realizado. Tentem alterar as prioridades das travas e testem para conferir o resultado.

public class Main {
	
	
	static long resultado = 0;
	static long quantidade = 100000;
	
	static int tcalled[] = new int[5];
	
	public static void main(String[] cmd) {
		final ConcurrencyLock lock = new ConcurrencyLock();
		
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				while (quantidade > 0) {
					if (lock.tryAcquire(0)) {
						if (quantidade-- > 0) {
							resultado += 1;
							tcalled[0]++;
						}
						lock.release();
					}
				}
			}
		});
		
		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				while (quantidade > 0) {
					if (lock.tryAcquire(1)) {
						if (quantidade-- > 0) {
							resultado += 5;
							tcalled[1]++;
						}
						lock.release();
					}
				}
			}
		});
		
		Thread t3 = new Thread(new Runnable() {
			@Override
			public void run() {
				while (quantidade > 0) {
					if (lock.tryAcquire(2)) {
						if (quantidade-- > 0) {
							resultado += 10;
							tcalled[2]++;
						}
						lock.release();
					}
				}
			}
		});
		
		Thread t4 = new Thread(new Runnable() {
			@Override
			public void run() {
				while (quantidade > 0) {
					if (lock.tryAcquire(3)) {
						if (quantidade-- > 0) {
							resultado += 15;
							tcalled[3]++;
						}
						lock.release();
					}
				}
			}
		});
		
		Thread t5 = new Thread(new Runnable() {
			@Override
			public void run() {
				while (quantidade > 0) {
					if (lock.tryAcquire(4)) {
						if (quantidade-- > 0) {
							resultado += 20;
							tcalled[4]++;
						}
						lock.release();
					}
				}
			}
		});
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		t5.start();
		
		try {
			t1.join();
			t2.join();
			t3.join();
			t4.join();
			t5.join();
		} catch (Exception e) {
		}
		
		
		int all = 0;
		for (int i = 0; i < 5; i++) {
			all += tcalled[i];
			System.out.println("Thread " + i + " realizou " + tcalled[i] + " operações.");
		}
		System.out.println("Foram realizadas " + all + " operações.");
		System.out.println("O resultado de todas operações foi: " + resultado);
	}
}

Bom uso, e caso tenham alguma duvida me perguntem. E me desculpem pelo meu Português. :(

Criado 15 de julho de 2014
Respostas 0
Participantes 1