上一篇生产者消费者模型中我们使用的是synchronize锁,选择我们需要换成Lock锁
Lock和synchronize的区别(synchronize的是随机抢到时间片,Lock可以按照顺序抢时间片精确让某个线程signal:condition配多把钥匙)
补充:notity并不会立即释放锁,需要等到执行notify()方法的线程将程序执行完,也就是退出synchronized代码块后,当前线程才会释放锁Lock的让出时间片的方式也是一样的
- Lock是一个接口,而synchronized是关键字。
- synchronized会自动释放锁,而Lock必须手动释放锁。
- Lock可以让等待锁的线程响应中断,而synchronized不会,线程会一直等待下去。
- 通过Lock可以知道线程有没有拿到锁,而synchronized不能。
- Lock能提高多个线程读操作的效率。
- synchronized能锁住类、方法和代码块,而Lock是块范围内的
- synchronize的通知唤醒用的是wait()和notify,Lock使用的是Condition里面的await() 和signal();
把synchronize的锁换成Lock(并发中的判断最好用while而不要用if为了防止线程的虚假唤醒)
任务:生产一个抢一个一直循环

package work; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; class MaiPiao{ private int piao=0; public int bbbb=30; Lock lock = new ReentrantLock(); public synchronized void incry() throws Exception { while (piao != 0) this.wait(); piao ++; System.out.println(Thread.currentThread().getName()+ "线程加了一个 现在还有:"+piao); Thread.sleep(300); this.notifyAll();} public synchronized void decry() throws Exception { while (piao == 0 ) this.wait(); Thread.sleep(500); piao--; System.out.println(Thread.currentThread().getName()+ "线程加了一个 现在还有:"+piao); this.notifyAll();}} public class Shangguigu { public static void main(String[] args) throws Exception { MaiPiao maiPiao = new MaiPiao(); new Thread(()->{for (int i = 0; i < 10; i++) { try { maiPiao.incry(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }}},"A").start(); new Thread(()->{for (int i = 0; i < 10; i++) { try { maiPiao.decry(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }}},"B").start();}}

package work; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; class MaiPiao{ private int piao=0; Lock lock = new ReentrantLock(); Condition condition = lock.newCondition(); public void incry() throws Exception { lock.lock(); try { while (piao != 0) condition.await(); piao ++; System.out.println(Thread.currentThread().getName()+ "线程加了一个 现在还有:"+piao); Thread.sleep(300); condition.signalAll(); }catch (Exception e) { // TODO: handle exception }finally { lock.unlock(); } } public void decry() throws Exception { lock.lock(); try { while (piao == 0 ) condition.await(); Thread.sleep(500); piao--; System.out.println(Thread.currentThread().getName()+ "线程加了一个 现在还有:"+piao); condition.signalAll(); }catch (Exception e) { // TODO: handle exception }finally { lock.unlock(); }} } public class Shangguigu { public static void main(String[] args) throws Exception { MaiPiao maiPiao = new MaiPiao(); new Thread(()->{for (int i = 0; i < 10; i++) { try { maiPiao.incry(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }}},"A").start(); new Thread(()->{for (int i = 0; i < 10; i++) { try { maiPiao.decry(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }}},"B").start(); } }
任务:线程A打印五次,线程B打印10次,线程C打印15次(可以一个lock配多个condition来指定signal:awite和signal的相互搭配使用的)

package work; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; class MaiPiao{ // 由于要按照顺序ABC的执行 判断 操作 // 首先要有执行的内容 // 其次多线程打印而且要按照顺序,所以要做一个顺序的标志位 // 由于是多线程首先要加锁 // private int flag = 1; //从1开始 private Lock lock = new ReentrantLock(); // 创建三个condition Condition work1 = lock.newCondition(); Condition work2 = lock.newCondition(); Condition work3 = lock.newCondition(); public void work1() throws Exception { lock.lock(); while (flag !=1) { work1.await(); } try { System.out.println(Thread.currentThread().getName()+" 正在打印 5 "); flag=2; work2.signal(); }catch (Exception e) { // TODO: handle exception }finally { lock.unlock();}} public void work2() throws Exception { lock.lock(); while (flag !=2) { work2.await(); } try { System.out.println(Thread.currentThread().getName()+" 正在打印 10 "); flag=3; work3.signal(); }catch (Exception e) { // TODO: handle exception }finally { lock.unlock();}} public void work3() throws Exception { lock.lock(); while (flag !=3) { work3.await(); } try { System.out.println(Thread.currentThread().getName()+" 正在打印 15 "); flag=1; work1.signal(); }catch (Exception e) { // TODO: handle exception }finally { lock.unlock();}} } public class Shangguigu { public static void main(String[] args) throws Exception { MaiPiao maiPiao = new MaiPiao(); new Thread(() -> { try { for (int i = 0; i < 3; i++) maiPiao.work1(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }, "A").start(); new Thread(() -> { try { for (int i = 0; i < 3; i++) maiPiao.work2(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }, "B").start(); new Thread(() -> { try { for (int i = 0; i < 3; i++) maiPiao.work3(); //循环三次 } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }, "C").start(); } }
# 四个创建线程的方法要记得