Java多线程-Lock锁的使用,以及生产者和消费者的实现

来源:互联网 发布:数据存储格式 编辑:程序博客网 时间:2024/06/05 16:27

本文中将主要介绍Java多线程编程基础中的Lock锁对象的使用,以及如何一步一步实现Java代码的生产者与消费者;

1、Java中如何使用Lock锁以及死锁问题的描述
2、Java实现生产者与消费者的过程(一步一步优化的步骤)


1、Java中如何使用Lock锁以及死锁问题的描述
LOCK锁的出现:为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象LOCK;
Lock锁中最重要的个方法:
void lock()
void unlock()
下面就是Lock锁的一个简单的演示Demo,之后的死锁问题也会使用Lock锁来进行表现;


1)例子一:利用Lock对象实现售票机制:


SellTicket.java

import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class SellTicket implements Runnable {    // 定义票    private int tickets = 100;    // 定义锁对象    private Lock lock = new ReentrantLock();    @Override    public void run() {        while (tickets > 0) {            // 之所以不带catch是因为保证在出错的情况下保证锁的释放            try{                // 加锁                lock.lock();                if (tickets > 0) {                    try {                        Thread.sleep(100);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets-- + "张票" );                }            } finally {                // 释放锁                lock.unlock();            }        }    }}

SellTicketDemo.java

public class SellTicketDemo {    public static void main(String[] args) {        // 创建资源对象        SellTicket st = new SellTicket();        // 创建窗口        Thread thread1 = new Thread(st, "窗口一");        Thread thread2 = new Thread(st, "窗口二");        Thread thread3 = new Thread(st, "窗口三");        // 开启线程        thread1.start();        thread2.start();        thread3.start();    }   }

运行效果:
Lock锁运行效果
可以看见线程在运行的时候,基本上都是成片运行的,并没有比较好的交叉运行


2)例子二:利用Lock实现死锁机制


MyLock.java

 /** * 创建两把锁可以直接调用 * @author YQ * */public class MyLock {    //创建两把锁对象    public static final Object objA = new Object();    public static final Object objB = new Object();}

DieLock.java

public class DieLock extends Thread {    private boolean flag;    public DieLock(boolean flag) {        this.flag = flag;    }    @Override    public void run() {        if (flag) {            synchronized (MyLock.objA) {                System.out.println("if ObjA");                synchronized (MyLock.objB) {                    System.out.println("if ObjB");                }            }        } else {            synchronized (MyLock.objB) {                System.out.println("else ObjB");                synchronized (MyLock.objA) {                    System.out.println("else ObjA");                }            }        }    }}

DieLockDemo.java

/** * 同步的弊端: *  A:效率低 *  B:容易产生死锁 * 死锁: *  两个或者两个以上的线程在争夺资源的过程中,发生的一种互相等待的现象 * @author YQ */public class DieLockDemo {    public static void main(String[] args) {        DieLock dieLock1 = new DieLock(true);        DieLock dieLock2 = new DieLock(false);        dieLock1.start();        dieLock2.start();    }}

运行效果:

死锁效果图


2、Java实现生产者与消费者的过程(一步一步优化的步骤)


1)初始实现,定义一个Student的JavaBean的类,然后通过set保存Student的数据作为生产者,之后通过get取出Student的数据作为消费者,但是以下的实现仅仅只有一次!
Student.java

public class Student {    private String name;    private int age;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    @Override    public String toString() {        return "Student [name=" + name + ", age=" + age + "]";    }}

SetThread.java

public class SetThread extends Thread{    private Student student;    public SetThread(Student student) {        super();        this.student = student;    }    @Override    public void run() {        student.setName("admin");        student.setAge(24);    }}

GetThread.java

public class GetThread extends Thread {    private Student student;    public GetThread(Student student) {        super();        this.student = student;    }    @Override    public void run() {        System.out.println(student.getName() + "====" + student.getAge());    }}

StudentDemo.java

public class StudentDemo {    public static void main(String[] args) {        // 创建两个线程的共用资源        Student student = new Student();        // 创建生产者和消费者        SetThread thread1 = new SetThread(student);        GetThread thread2 = new GetThread(student);        //开启生产者和消费者线程        thread1.start();        thread2.start();    }}

运行效果:
生产者消费者例子1运行效果


2)进一步的循环实现多次生产多次消费,使用的是同步的方式
Student.java代码同上!


GetThread.java

public class GetThread extends Thread {    private Student student;    public GetThread(Student student) {        super();        this.student = student;    }    @Override    public void run() {        while (true) {            synchronized (student) {                System.out.println(student.getName() + "====" + student.getAge());            }        }    }}

SetThread.java

public class SetThread extends Thread{    private Student student;    private int x = 0;    public SetThread(Student student) {        super();        this.student = student;    }    @Override    public void run() {        while (true) {            //必须是相同的同一把锁            synchronized (student) {                if (x%2 == 0) {                    student.setName("admin");                    student.setAge(24);                } else {                    student.setName("manager");                    student.setAge(28);                }                x++;            }               }     }}

StudentDemo.java

public class StudentDemo {    public static void main(String[] args) {        // 创建两个线程的共用资源        Student student = new Student();        // 创建生产者和消费者        SetThread thread1 = new SetThread(student);        GetThread thread2 = new GetThread(student);        //开启生产者和消费者线程        thread1.start();        thread2.start();    }}

运行效果(停止的时候出现的ad没有完整与线程的实现没有关系,主要是因为命令窗口的缓冲没有完整的原因):
运行效果


3)真正实现生产者与消费者:生产者生产后消费者才可以消费,消费者消费之后生产者才可以生产如此往复:


Student.java

public class Student {    private String name;    private int age;    //默认情况下不存在数据    private boolean flag;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    public boolean isFlag() {        return flag;    }    public void setFlag(boolean flag) {        this.flag = flag;    }    @Override    public String toString() {        return "Student [name=" + name + ", age=" + age + "]";    }}

SetThread.java

public class SetThread extends Thread{    private Student student;    private int x = 0;    public SetThread(Student student) {        super();        this.student = student;    }    @Override    public void run() {        while (true) {            // 必须是相同的同一把锁            synchronized (student) {                // 判断                if (student.isFlag()) {                    try {                        student.wait();                    } catch (InterruptedException e) {                        // TODO Auto-generated catch block                        e.printStackTrace();                    }                }                if (x%2 == 0) {                    student.setName("admin");                    student.setAge(24);                } else {                    student.setName("manager");                    student.setAge(28);                }                x++;                // 修改标记                student.setFlag(true);                student.notify();            }        }     }}

GetThread.java

public class GetThread extends Thread {    private Student student;    public GetThread(Student student) {        super();        this.student = student;    }    @Override    public void run() {        while (true) {            synchronized (student) {                if (!student.isFlag()) {                    try {                        student.wait();                    } catch (InterruptedException e) {                        // TODO Auto-generated catch block                        e.printStackTrace();                    }                }                System.out.println(student.getName() + "====" + student.getAge());                student.setFlag(false);                student.notify();            }        }    }}

运行效果:
StudentDemo.java

/** * 等待唤醒: *      Object类中提供了三个方法: *      wait():等待; *      notify():唤醒单个线程; *      notifyAll():唤醒所有线程; * @author YQ * */public class StudentDemo {    public static void main(String[] args) {        // 创建两个线程的共用资源        Student student = new Student();        // 创建生产者和消费者        SetThread thread1 = new SetThread(student);        GetThread thread2 = new GetThread(student);        //开启生产者和消费者线程        thread1.start();        thread2.start();    }}

运行效果:
StudentDemo的运行效果

0 0
原创粉丝点击