📜  如何在多线程Java程序中使用锁?

📅  最后修改于: 2022-05-13 01:55:34.557000             🧑  作者: Mango

如何在多线程Java程序中使用锁?

锁可能是一种比标准同步块更灵活和复杂的线程同步机制。锁可以是控制多个线程访问共享资源的工具。通常,锁提供对共享资源的独占访问:一次只有一个线程可以获取锁,并且每个人访问共享资源都需要先获取锁。但是,某些锁可能允许并发访问共享资源,例如 ReadWriteLock 的读锁。

// Example of lock interface
Lock lock = new ReentrantLock();
lock.lock();
 
// critical section 
lock.unlock();

锁接口中的方法

锁接口中有一些方法。我们将看看那些及其修饰符:

MODIFIERSDESCRIPTION
voidlock() – 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
conditionnewCondition() – It simply returns the new condition instance
booleantryLock() – 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 上运行。