如何在多线程Java程序中使用锁?
锁可能是一种比标准同步块更灵活和复杂的线程同步机制。锁可以是控制多个线程访问共享资源的工具。通常,锁提供对共享资源的独占访问:一次只有一个线程可以获取锁,并且每个人访问共享资源都需要先获取锁。但是,某些锁可能允许并发访问共享资源,例如 ReadWriteLock 的读锁。
// Example of lock interface
Lock lock = new ReentrantLock();
lock.lock();
// critical section
lock.unlock();
锁接口中的方法
锁接口中有一些方法。我们将看看那些及其修饰符:MODIFIERS DESCRIPTION void lock() – It acquires the lock if it’s available; if the lock isn’t available a thread gets blocked until the lock is released lockInterruptibly() – It is similar to lock() but it acquires the lock unless the thread is interrupted unlock() – As the name suggests it simply releases the lock instance condition newCondition() – It simply returns the new condition instance boolean tryLock() – It attempts to accumulate the lock immediately, return true if locking succeeds tryLock(long time, TimeUnit unit) – It is often almost like tryLock(), except it waits up the given timeout before abandoning trying to accumulate the Lock
锁的实现
让我们看看我们如何在Java中实现一些锁:
1.readWriteLock()
ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
readWriteLock.readLock().lock();
// ....
......//
readWriteLock.readLock().unlock();
readWriteLock.writeLock().lock();
// only one writer can enter this section,
// and only if no threads are currently reading.
readWriteLock.writeLock().unlock();
下面是 readWriteLock() 方法的实现:
Java
// Implementation of ReadWriteLock in Java
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
class GFG {
private final ReadWriteLock readWriteLock
= new ReentrantReadWriteLock();
private final Lock writeLock
= readWriteLock.writeLock();
private final Lock readLock = readWriteLock.readLock();
private final List list = new ArrayList<>();
// setElement function sets
// i.e., write the element to the thread
public void setElement(O o)
{
// acquire the thread for writing
writeLock.lock();
try {
list.add(o);
System.out.println(
"Element by thread "
+ Thread.currentThread().getName()
+ " is added");
}
finally {
// To unlock the acquired write thread
writeLock.unlock();
}
}
// getElement function prints
// i.e., read the element from the thread
public O getElement(int i)
{
// acquire the thread for reading
readLock.lock();
try {
System.out.println(
"Elements by thread "
+ Thread.currentThread().getName()
+ " is printed");
return list.get(i);
}
finally {
// To unlock the acquired read thread
readLock.unlock();
}
}
public static void main(String[] args)
{
GFG gfg = new GFG<>();
gfg.setElement("Hi");
gfg.setElement("Hey");
gfg.setElement("Hello");
System.out.println("Printing the last element : "
+ gfg.getElement(2));
}
}
Java
// Java code to illustrate Reentrant Locks
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantLock;
class worker implements Runnable {
String name;
ReentrantLock re;
public worker(ReentrantLock rl, String n)
{
re = rl;
name = n;
}
public void run()
{
boolean done = false;
while (!done) {
// Getting Outer Lock
boolean ans = re.tryLock();
// Returns True if lock is free
if (ans) {
try {
Date d = new Date();
SimpleDateFormat ft
= new SimpleDateFormat("hh:mm:ss");
System.out.println(
"task name - " + name
+ " outer lock acquired at "
+ ft.format(d)
+ " Doing outer work");
Thread.sleep(1500);
// Getting Inner Lock
re.lock();
try {
d = new Date();
ft = new SimpleDateFormat(
"hh:mm:ss");
System.out.println(
"task name - " + name
+ " inner lock acquired at "
+ ft.format(d)
+ " Doing inner work");
System.out.println(
"Lock Hold Count - "
+ re.getHoldCount());
Thread.sleep(1500);
}
catch (InterruptedException e) {
e.printStackTrace();
}
finally {
// Inner lock release
System.out.println(
"task name - " + name
+ " releasing inner lock");
re.unlock();
}
System.out.println("Lock Hold Count - "
+ re.getHoldCount());
System.out.println("task name - " + name
+ " work done");
done = true;
}
catch (InterruptedException e) {
e.printStackTrace();
}
finally {
// Outer lock release
System.out.println(
"task name - " + name
+ " releasing outer lock");
re.unlock();
System.out.println("Lock Hold Count - "
+ re.getHoldCount());
}
}
else {
System.out.println("task name - " + name
+ " waiting for lock");
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public class test {
static final int MAX_T = 2;
public static void main(String[] args)
{
ReentrantLock rel = new ReentrantLock();
ExecutorService pool
= Executors.newFixedThreadPool(MAX_T);
Runnable w1 = new worker(rel, "Job1");
Runnable w2 = new worker(rel, "Job2");
Runnable w3 = new worker(rel, "Job3");
Runnable w4 = new worker(rel, "Job4");
pool.execute(w1);
pool.execute(w2);
pool.execute(w3);
pool.execute(w4);
pool.shutdown();
}
}
Element by thread main is added
Element by thread main is added
Element by thread main is added
Elements by thread main is printed
Printing the last element : Hello
2. reentrantLock()
public class lockImplement {
//...
ReentrantLock lock = new ReentrantLock();
int counter = 0;
public void testing() {
lock.lock();
try {
// Critical section here
count++;
} finally {
lock.unlock();
}
}
//...
}
下面是 reentrantLock() 方法的实现:
Java
// Java code to illustrate Reentrant Locks
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantLock;
class worker implements Runnable {
String name;
ReentrantLock re;
public worker(ReentrantLock rl, String n)
{
re = rl;
name = n;
}
public void run()
{
boolean done = false;
while (!done) {
// Getting Outer Lock
boolean ans = re.tryLock();
// Returns True if lock is free
if (ans) {
try {
Date d = new Date();
SimpleDateFormat ft
= new SimpleDateFormat("hh:mm:ss");
System.out.println(
"task name - " + name
+ " outer lock acquired at "
+ ft.format(d)
+ " Doing outer work");
Thread.sleep(1500);
// Getting Inner Lock
re.lock();
try {
d = new Date();
ft = new SimpleDateFormat(
"hh:mm:ss");
System.out.println(
"task name - " + name
+ " inner lock acquired at "
+ ft.format(d)
+ " Doing inner work");
System.out.println(
"Lock Hold Count - "
+ re.getHoldCount());
Thread.sleep(1500);
}
catch (InterruptedException e) {
e.printStackTrace();
}
finally {
// Inner lock release
System.out.println(
"task name - " + name
+ " releasing inner lock");
re.unlock();
}
System.out.println("Lock Hold Count - "
+ re.getHoldCount());
System.out.println("task name - " + name
+ " work done");
done = true;
}
catch (InterruptedException e) {
e.printStackTrace();
}
finally {
// Outer lock release
System.out.println(
"task name - " + name
+ " releasing outer lock");
re.unlock();
System.out.println("Lock Hold Count - "
+ re.getHoldCount());
}
}
else {
System.out.println("task name - " + name
+ " waiting for lock");
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public class test {
static final int MAX_T = 2;
public static void main(String[] args)
{
ReentrantLock rel = new ReentrantLock();
ExecutorService pool
= Executors.newFixedThreadPool(MAX_T);
Runnable w1 = new worker(rel, "Job1");
Runnable w2 = new worker(rel, "Job2");
Runnable w3 = new worker(rel, "Job3");
Runnable w4 = new worker(rel, "Job4");
pool.execute(w1);
pool.execute(w2);
pool.execute(w3);
pool.execute(w4);
pool.shutdown();
}
}
输出:
task name - Job2 waiting for lock
task name - Job1 outer lock acquired at 09:49:42 Doing outer work
task name - Job2 waiting for lock
task name - Job1 inner lock acquired at 09:49:44 Doing inner work
Lock Hold Count - 2
task name - Job2 waiting for lock
task name - Job2 waiting for lock
task name - Job1 releasing inner lock
Lock Hold Count - 1
task name - Job1 work done
task name - Job1 releasing outer lock
Lock Hold Count - 0
task name - Job3 outer lock acquired at 09:49:45 Doing outer work
task name - Job2 waiting for lock
task name - Job3 inner lock acquired at 09:49:47 Doing inner work
Lock Hold Count - 2
task name - Job2 waiting for lock
task name - Job2 waiting for lock
task name - Job3 releasing inner lock
Lock Hold Count - 1
task name - Job3 work done
task name - Job3 releasing outer lock
Lock Hold Count - 0
task name - Job4 outer lock acquired at 09:49:48 Doing outer work
task name - Job2 waiting for lock
task name - Job4 inner lock acquired at 09:49:50 Doing inner work
Lock Hold Count - 2
task name - Job2 waiting for lock
task name - Job2 waiting for lock
task name - Job4 releasing inner lock
Lock Hold Count - 1
task name - Job4 work done
task name - Job4 releasing outer lock
Lock Hold Count - 0
task name - Job2 outer lock acquired at 09:49:52 Doing outer work
task name - Job2 inner lock acquired at 09:49:53 Doing inner work
Lock Hold Count - 2
task name - Job2 releasing inner lock
Lock Hold Count - 1
task name - Job2 work done
task name - Job2 releasing outer lock
Lock Hold Count - 0
注意:由于睡眠调用,该程序可能无法在在线 IDE 上运行。