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:
[code]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;
}
};
}[/code]
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.