您的位置 首页 java

工作十年的java工程师告诉你如何使用lock

我们已经了解了线程同步的基本概念以及使用synchronized关键字的各种机制。Java提供了另一种基于锁接口和实现它的类(如ReNANTTROLK)同步代码块的机制。在本教程中,我们将看到锁接口的基本用法,以解决打印机队列问题。

Lock Interface

java.util.concurrent.locks.lock是一种线程同步机制,与同步块类似。然而,使用lock比同步块更灵活、更复杂。由于lock是一个接口,所以需要使用它的一个实现来在应用程序中使用lock。ReentrantLock是锁接口的一种实现。

下面是锁接口的简单用法。

Lock lock = new ReentrantLock();

lock.lock();

//critical section

lock.unlock();

上面首先创建一个锁的实例。然后调用它的lock()方法。现在实例被锁定。调用lock()的任何其他线程将被阻塞,直到锁定该锁的线程调用unlock()。

最后调用unlock(),lock现在被解锁,以便其他线程可以锁定它。

Lock Interface和synchronized关键字之间的区别

Lock和synchronized块之间的主要区别是:

1)尝试访问同步块时发生超时是不可能的。 使用Lock.tryLock(长超时,TimeUnit timeUnit),这是可能的。

2) synchronized 必须完全包含在单个方法中。 Lock可以在单独的方法中调用lock()和unlock()。

使用lock模拟打印机队列

在本例中,程序将模拟打印机的行为。您可以在不同的时间间隔或同时向打印机提交多个打印作业。打印机将从打印机队列中获取一个作业并打印它。其余的工作将 在那里 等待。一旦打印机完成手头的打印作业,它将从队列中选择另一个作业并开始打印。然后再循环。

PrintingJob.java

此类表示可以提交给打印机的打印工作。这个类实现了可运行的接口,这样打印机可以在轮到它时执行它。

class PrintingJob implements Runnable

{

private PrinterQueue printerQueue;

public PrintingJob(PrinterQueue printerQueue)

{

this .printerQueue = printerQueue;

}

@Override

public void run()

{

System.out.printf(“%s: Going to print a documentn”, Thread.currentThread().getName());

printerQueue.printJob( new Object());

}

}

PrinterQueue.java

此类表示打印机队列/打印机。 当前打印作业完成后,打印机将保持锁定以启动新的打印作业。

class PrinterQueue

{

private final Lock queueLock = new ReentrantLock();

public void printJob(Object document)

{

queueLock.lock();

try

{

Long duration = ( long ) (Math.random() * 10000);

System.out.println(Thread.currentThread().getName() + “: PrintQueue: Printing a Job during ” + (duration / 1000) + ” seconds :: Time – ” + new Date());

Thread.sleep(duration);

} catch (InterruptedException e)

{

e.printStackTrace();

} finally

{

System.out.printf(“%s: The document has been printedn”, Thread.currentThread().getName());

queueLock.unlock();

}

}

}

让我们测试一下打印机程序:

public class LockExample

{

public static void main(String[] args)

{

PrinterQueue printerQueue = new PrinterQueue();

Thread thread[] = new Thread[10];

for ( int i = 0; i < 10; i++)

{

thread[i] = new Thread( new PrintingJob(printerQueue), “Thread ” + i);

}

for ( int i = 0; i < 10; i++)

{

thread[i].start();

}

}

}

最终输出:

Thread 0: Going to print a document

Thread 9: Going to print a document

Thread 8: Going to print a document

Thread 7: Going to print a document

Thread 5: Going to print a document

Thread 6: Going to print a document

Thread 4: Going to print a document

Thread 3: Going to print a document

Thread 2: Going to print a document

Thread 1: Going to print a document

Thread 0: PrintQueue: Printing a Job during 8 seconds :: Time – Tue Jan 06 15:19:02 IST 2015

Thread 0: The document has been printed

Thread 9: PrintQueue: Printing a Job during 1 seconds :: Time – Tue Jan 06 15:19:11 IST 2015

Thread 9: The document has been printed

Thread 8: PrintQueue: Printing a Job during 8 seconds :: Time – Tue Jan 06 15:19:12 IST 2015

Thread 8: The document has been printed

Thread 7: PrintQueue: Printing a Job during 9 seconds :: Time – Tue Jan 06 15:19:21 IST 2015

Thread 7: The document has been printed

Thread 5: PrintQueue: Printing a Job during 7 seconds :: Time – Tue Jan 06 15:19:31 IST 2015

Thread 5: The document has been printed

Thread 6: PrintQueue: Printing a Job during 5 seconds :: Time – Tue Jan 06 15:19:39 IST 2015

Thread 6: The document has been printed

Thread 4: PrintQueue: Printing a Job during 2 seconds :: Time – Tue Jan 06 15:19:44 IST 2015

Thread 4: The document has been printed

Thread 3: PrintQueue: Printing a Job during 2 seconds :: Time – Tue Jan 06 15:19:46 IST 2015

Thread 3: The document has been printed

Thread 2: PrintQueue: Printing a Job during 5 seconds :: Time – Tue Jan 06 15:19:49 IST 2015

Thread 2: The document has been printed

Thread 1: PrintQueue: Printing a Job during 5 seconds :: Time – Tue Jan 06 15:19:54 IST 2015

Thread 1: The document has been printed

该示例的关键点是PrinterQueue类的printJob()方法。 当我们想要使用lock实现一个critical section并保证只有一个执行线程运行一个代码块时,我们必须创建一个ReentrantLock对象。 在critical section的开头,我们必须使用lock()方法来控制锁。

在critical section的末尾,我们必须使用unlock()方法释放对锁的控制,并允许其他线程运行这个critical section。如果不在critical section的末尾调用unlock()方法,则等待该块的其他线程将永远等待,从而导致死锁情况。如果在critical section使用try catch块,请不要忘记将包含unlock()方法的语句放在finally部分中。

如果你喜欢请收藏!

文章来源:智云一二三科技

文章标题:工作十年的java工程师告诉你如何使用lock

文章地址:https://www.zhihuclub.com/195638.shtml

关于作者: 智云科技

热门文章

网站地图