同步代码块实现生产者消费者模式
class Person { private String name; private String sex; private Boolean isEmpty = Boolean.TRUE; // 表示存储区域是否为空 //生产 public void set(String name, String sex) { synchronized (this) { // if(isEmpty) while (!isEmpty.equals(Boolean.TRUE)) { // 区域不为空,此时生产者应该停下来,等着消费者消费 try {this.wait();// 等待 消费者消费} catch (InterruptedException e) {} } this.name = name; try {Thread.sleep(1); } catch (InterruptedException e) {e.printStackTrace();} this.sex = sex; // 生产者生产之后,应该修改存储区域的状态 isEmpty = Boolean.FALSE;// 不为空 this.notifyAll();// 唤醒消费者,起来吃东西了 } } //消费 public void get() { synchronized (this) { // 存储区域为空 while (!isEmpty.equals(Boolean.FALSE)) { try {this.wait();// 等着生产者去生产} catch (InterruptedException e) {} } String name = getName(); String sex = getSex(); System.out.println(name + " --> " + sex); // 消费完成,应该修改存储区域的状态 isEmpty = Boolean.TRUE;// 空了 this.notifyAll();// 唤醒生产者, } } getter/setter } //生产者 class Producer implements Runnable { private Person p; public Producer(Person p) { this.p = p; } public void run() { for (int i = 0; i < 100; i++) { if (i % 2 == 0) { p.set("春哥哥", "男"); } else { p.set("著姐", "女"); } } } } //消费者 class Consumer implements Runnable { private Person p; public Consumer(Person p) { this.p = p; } public void run() { for (int i = 0; i < 100; i++) { p.get(); } } } public class Producer_ConsumerDemo { public static void main(String[] args) { Person p = new Person(); new Thread(new Producer(p)).start(); new Thread(new Consumer(p)).start(); new Thread(new Producer(p)).start(); new Thread(new Consumer(p)).start(); } }
同步方法实现生产者消费者模式
class Person { private String name; private String sex; private Boolean isEmpty = Boolean.TRUE; // 表示存储区域是否为空 //生产 public synchronized void set(String name, String sex) { // if(isEmpty) while (!isEmpty.equals(Boolean.TRUE)) { // 区域不为空,此时生产者应该停下来,等着消费者消费 try {this.wait();// 等待 消费者消费} catch (InterruptedException e) {} } this.name = name; try {Thread.sleep(1); } catch (InterruptedException e) {} this.sex = sex; // 生产者生产之后,应该修改存储区域的状态 isEmpty = Boolean.FALSE;// 不为空 this.notifyAll();// 唤醒消费者,起来吃东西了 } //消费 public synchronized void get() { // 存储区域为空 while (!isEmpty.equals(Boolean.FALSE)) { try {this.wait();// 等着生产者去生产} catch (InterruptedException e) {} } String name = getName(); String sex = getSex(); System.out.println(name + " --> " + sex); // 消费完成,应该修改存储区域的状态 isEmpty = Boolean.TRUE;// 空了 this.notifyAll();// 唤醒生产者, } getter/setter } //生产者 class Producer implements Runnable { private Person p; public Producer(Person p) { this.p = p; } public void run() { for (int i = 0; i < 100; i++) { if (i % 2 == 0) { p.set("春哥哥", "男"); } else { p.set("著姐", "女"); } } } } class Consumer implements Runnable { private Person p; public Consumer(Person p) { this.p = p; } public void run() { for (int i = 0; i < 100; i++) { p.get(); } } } public class Producer_ConsumerDemo { public static void main(String[] args) { Person p = new Person(); new Thread(new Producer(p)).start(); new Thread(new Consumer(p)).start(); new Thread(new Producer(p)).start(); new Thread(new Consumer(p)).start(); } }
可重入锁实现生产者消费者模式
jkd1.5后的另一种同步机制:通过显示定义同步锁对象来实现同步,这种机制,同步锁应该使用Lock对象充当;
在实现线程安全控制中,通常使用ReentrantLock(可重入锁)。使用该对象可以显示地加锁和解锁;
具有与使用 synchronized 方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大。
格式:
public class X { private final ReentrantLock lock = new ReentrantLock(); //定义需要保证线程安全的方法 public void m(){ lock.lock();//加锁 try{ //... method body }finally{ lock.unlock();//在finally释放锁 } } }
可重入锁没有同步监听对象,咋办呢?
Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。
class Person { private final ReentrantLock lock = new ReentrantLock();// 创建可重入锁对象 private final Condition con = lock.newCondition(); private String name; private String sex; private Boolean isEmpty = Boolean.TRUE; // 表示存储区域是否为空 //生产 public void set(String name, String sex) { lock.lock(); while(!isEmpty.equals(Boolean.TRUE)){ //表示不空状态 try {con.await();} catch (InterruptedException e) {}} try { this.name = name; Thread.sleep(1); this.sex = sex; isEmpty = Boolean.FALSE; con.signal(); } catch (InterruptedException e) {} finally { lock.unlock(); } } //消费 public void get() { lock.lock(); while(!isEmpty.equals(Boolean.FALSE)){ //存储区域为空,消费者应该等着 try { con.await(); } catch (InterruptedException e) { e.printStackTrace(); } } try { String name = getName(); String sex = getSex(); System.out.println(name + " --> " + sex); // isEmpty = Boolean.TRUE; con.signal(); } finally { lock.unlock(); } } getter/setter } //生产者 class Producer implements Runnable { private Person p; public Producer(Person p) { this.p = p; } public void run() { for (int i = 0; i < 100; i++) { if (i % 2 == 0) { p.set("春哥哥", "男"); } else { p.set("著姐", "女"); } } } } class Consumer implements Runnable { private Person p; public Consumer(Person p) { this.p = p; } public void run() { for (int i = 0; i < 100; i++) { p.get(); } } } public class Producer_ConsumerDemo { public static void main(String[] args) { Person p = new Person(); new Thread(new Producer(p)).start(); new Thread(new Consumer(p)).start(); } }
同步代码块方式改写卖票程序
class MyRunnable implements Runnable { private Integer num = 50; public void run() { for (int i = 0; i < 200; i++) { sale(); } } private Object o = new Object(); public void sale() { // synchronized (this) { // synchronized (MyRunnable.class) { synchronized (o) { if (num > 0) { try {Thread.sleep(1); } catch (InterruptedException e) {} System.out.println(Thread.currentThread().getName() + "卖出第" + num-- + "张"); } } } } public class TicketDemoSyncByBlock { public static void main(String[] args) { Runnable target = new MyRunnable(); new Thread(target, "A").start(); new Thread(target, "B").start(); new Thread(target, "C").start(); } }
实现Runnable接口的方式,使用同步代码块的方式进行同步。
可以取的同步监听对象为:this、当前方法所在类的Class对象、任一不变对象;
同步方法方式改写卖票程序
class MyRunnable implements Runnable { private Integer num = 50; public void run() { for (int i = 0; i < 200; i++) { sale(); } } synchronized public void sale() { if (num > 0) { try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "卖出第" + num-- + "张"); } } } public class TicketDemoSyncByMethod { public static void main(String[] args) { Runnable target = new MyRunnable(); new Thread(target, "A").start(); new Thread(target, "B").start(); new Thread(target, "C").start(); } }
可重入锁方式改写卖票程序
class MyRunnable implements Runnable { private final ReentrantLock lock = new ReentrantLock(); private Integer num = 50; public void run() { for (int i = 0; i < 200; i++) { sale(); } } public void sale() { lock.lock(); try { if (num > 0) { try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "卖出第" + num-- + "张"); } } finally { lock.unlock(); } } } public class TicketDemoSyncByReentrantLock { public static void main(String[] args) { Runnable target = new MyRunnable(); new Thread(target, "A").start(); new Thread(target, "B").start(); new Thread(target, "C").start(); } }