Java多线程:Lock锁(未完待续)

Lock锁的基本使用

在Java中,Lock是一个接口,它提供了比synchronized关键字更高级的线程同步机制。使用Lock接口可以创建更复杂和灵活的同步结构。

Lock接口的常用实现类有ReentrantLock和ReentrantReadWriteLock,它们提供了可重入的互斥锁和读写锁。

相比synchronized来实现同步,使用Lock实现同步主要有以下差异性:

  1.  使用synchronized关键字时,锁的控制和释放是在synchronized同步代码块的开始和结束位置。而在使用Lock实现同步时,锁的获取和释放可以在不同的代码块、不同的方法中。这一点是基于使用者手动获取和释放锁的特性。
  2.  Lock接口提供了试图获取锁的tryLock()方法,在调用tryLock()获取锁失败时返回false,这样线程可以执行其它的操作 而不至于使线程进入休眠。tryLock()方法可传入一个long型的时间参数,允许在一定的时间内来获取锁。
  3.  Lock接口的实现类ReentrantReadWriteLock提供了读锁和写锁,允许多个线程获得读锁、而只能有一个线程获得写锁。读锁和写锁不能同时获得。实现了读和写的分离,这一点在需要并发读的应用中非常重要,如lucene允许多个线程读取索引数据进行查询但只能有一个线程负责索引数据的构建。
  4.  基于以上3点,lock来实现同步具备更好的性能。

使用Lock:

创建Lock对象。

// 创建Lock对象
Lock lock = new ReentrantLock();
```

在需要进行同步的代码块中,通过调用`lock()`方法来获取锁。

lock.lock();
try {
    // 同步的代码
} finally {
    // 在finally块中释放锁,以确保锁的释放
    lock.unlock();
}
```

示例代码如下,多种方式进行代码块同步:

package ch12;


import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


/**
 * @copyright 2003-2024
 * @author    qiao wei
 * @date      2024-01-10
 * @version   1.0
 * @brief     
 * @history   
 */
public class SellTicketThread extends Thread {
    
    public SellTicketThread() {
        ticket = 0;
        lock = new ReentrantLock();
    }

    @Override
    public void run() {
        super.run();
        
//        run01();
        runUseLock04();
    }
    
    private void runUseSynchronized() {
        while (true) {
            synchronized (SellTicketThread.class) {
                if (100 >= ticket) {
                    ++ticket;
//                    sleep(100);
                    System.out.println(getName() + "正在卖第" + ticket + "门票");
                } else {
                    break;
                }
            }
        }
    }
    
    /**
     * @author  qiao wei
     * @brief   先处理,后break流程。多处使用类Lock的unlock方法。
     * @param   
     * @return  
     * @throws  
     * @history 
     */
    private void runUseLock01() {
        while (true) {
            if (100 >= ticket) {
                lock.lock();
                if (100 >= ticket) {
                    ++ticket;
                    System.out.println(getName() + "正在卖第" + ticket + "门票");
                } else {
                    lock.unlock();
                    break;
                }

                lock.unlock();
            } else {
                // 退出while循环语句。
                break;
            }
        }
    }
    
    /**
     * @author  qiao wei
     * @brief   先处理,后break流程。使用try/finally流程处理类Lock的unlock方法。
     * @param   
     * @return  
     * @throws  
     * @history 
     */
    private void runUseLock02() {
        while (true) {
            if (100 >= ticket) {
                try {
                    lock.lock();
                    if (100 >= ticket) {
                        ++ticket;
                        System.out.println(getName() + "正在卖第" + ticket + "门票");
                    } else {
                        break;
                    }
                } finally {
                    // 唯一解锁处。
                    lock.unlock();
                }
            } else {
                // 退出while循环语句。
                break;
            }
        }
    }
    
    /**
     * @author  qiao wei
     * @brief   先break,后处理流程。多处使用类Lock的unlock方法。
     * @param   
     * @return  
     * @throws  
     * @history 
     */
    private void runUseLock03() {
        while (true) {
            if (100 == ticket) {
                break;
            } else {
                lock.lock();

                if (100 == ticket) {
                    lock.unlock();

                    // 退出while循环语句。
                    break;
                } else {
                    ++ticket;
                    System.out.println(getName() + "正在卖第" + ticket + "门票");
                }

                lock.unlock();
            }
        }
    }
    
    /**
     * @author  qiao wei
     * @brief   先break,后处理流程。使用try/finally流程处理类Lock的unlock方法。
     * @param   
     * @return  
     * @throws  
     * @history 
     */
    private void runUseLock04() {
        while (true) {
            if (100 == ticket) {
                break;
            } else {
                lock.lock();

                try {
                    if (100 == ticket) {
                        break;
                    } else {
                        ++ticket;
                        System.out.println(getName() + "正在卖第" + ticket + "门票");
                    }
                } finally {
                    lock.unlock();
                }
            }
        }
    }
    
    /**
     * @author qiao wei
     * @brief  要出售的总票数。
     */
    private static int ticket;
    
    /**
     * @author qiao wei
     * @brief  同步锁。
     */
    private static Lock lock;
}

测试验证:

package ch12;


/**
 * @copyright 2003-2024
 * @author    qiao wei
 * @date      2024-01-10
 * @version   1.0
 * @brief     
 * @history   
 */
public class TestSynchronized {
    
    public TestSynchronized() {}

    public static void main(String[] args) {
        SellTicketThread thread01 = new SellTicketThread();
        SellTicketThread thread02 = new SellTicketThread();
        SellTicketThread thread03 = new SellTicketThread();
        
        thread01.start();
        thread02.start();
        thread03.start();
    }
}

注意事项:

加锁(lock或synchronized)必须在循环(while)里面,不软会导致一个线程占用所有资源,而不是多线程切换。

你可能感兴趣的:(Java,开发语言,Java)