二:JAVA通知唤醒机制,Lock替换synchronize

上一篇生产者消费者模型中我们使用的是synchronize锁,选择我们需要换成Lock锁

  Lock和synchronize的区别(synchronize的是随机抢到时间片,Lock可以按照顺序抢时间片精确让某个线程signal:condition配多把钥匙)

   补充:notity并不会立即释放锁,需要等到执行notify()方法的线程将程序执行完,也就是退出synchronized代码块后,当前线程才会释放锁Lock的让出时间片的方式也是一样的

  1. Lock是一个接口,而synchronized是关键字。
  2. synchronized会自动释放锁,而Lock必须手动释放锁。
  3. Lock可以让等待锁的线程响应中断,而synchronized不会,线程会一直等待下去。
  4. 通过Lock可以知道线程有没有拿到锁,而synchronized不能。
  5. Lock能提高多个线程读操作的效率。
  6. synchronized能锁住类、方法和代码块,而Lock是块范围内的
  7. 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();}}
synchronize的通知唤醒机制
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();
        }
    }
Lock的唤醒机制

任务:线程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();
    }
}
Lock定向让出时间片

 

 

# 四个创建线程的方法要记得

 

posted @ 2020-12-07 20:25  晴晴小可爱的小弟  阅读(222)  评论(0编辑  收藏  举报