一、用Synchronized代码块
可以根据注释阅读代码
run()方法解析
package synchronized_compro;
/**
* 资源类(因为资源共享,所以要是单例)
* 属性:商品名称,商品编号,标识,单例引用
* */
public class Resource {
private static final Resource r=new Resource(); //单例
private String name; //商品名称
private int num=1; //商品编号
private boolean flag=false; //标识,用于标识是该生产还是消费
public void setFlag(boolean flag) {
this.flag = flag;
}
public boolean getFlag() {
return flag;
}
public void setName(String name) {
this.name = name+num;
num++;
}
public String getName() {
return name;
}
public static Resource getInstance() {
return r;
}
}
package synchronized_compro;
/**
* 生产类(生产一般是多个,所以用线程)
属性:资源的对象引用
行为:生产
*/
public class Producer implements Runnable {
private Resource r = Resource.getInstance(); // 单例
/* 生产 */
public void set(String name) {
r.setName("商品");
System.out.println(Thread.currentThread().getName() + " : 生产 " + r.getName());
}
@Override
public void run() {
// TODO Auto-generated method stub
while (true) {
synchronized (r) {
while (r.getFlag()) {
try {
r.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
set("商品");
r.setFlag(true);
r.notifyAll();
}
}
}
}
package synchronized_compro;
/**
* 消费类(消费一般是多个,所以用线程)
* 属性:资源的对象引用
* 行为:消费
* */
public class Consumer implements Runnable{
private Resource r=Resource.getInstance();//单例
/*消费*/
public void out() {
System.out.println(Thread.currentThread().getName()+" : 消费 "+r.getName());
}
@Override
public void run() {
// TODO Auto-generated method stub
while (true) {
synchronized (r) {
while (!r.getFlag()) {
try {
r.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
out();
r.setFlag(false);
r.notifyAll();
}
}
}
}
package synchronized_compro;
/**
* 测试类
* */
public class Demo {
public static void main(String[] args) {
Producer p=new Producer(); //实例化生产
Consumer c=new Consumer(); //实例化消费
Thread t1=new Thread(p);
Thread t2=new Thread(p);
Thread t3=new Thread(c);
Thread t4=new Thread(c);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
notifyAll()会造成浪费太多资源,降低性能。notify()会产生死锁。虽说可以使用两个synchronized嵌套代码块,但是这样也会造成死锁。
二、利用Lock替代synchronized,利用Condition来替代监视器方法
这样就可以解决只有一个锁难以解决占用资源的缺点
package compro;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 资源类(因为资源共享,所以要是单例)
* 属性:商品名称,商品编号
* */
public class Resource {
private static final Resource r=new Resource(); //资源
private String name; //商品名称
private int num=1; //商品编号
private boolean flag=false; //标识,用于标识是该生产还是消费
private static Lock lock=new ReentrantLock(); //锁实例
private static Condition con1=lock.newCondition(); //生产监视器
private static Condition con2=lock.newCondition(); //消费监视器
public void setFlag(boolean flag) {
this.flag = flag;
}
public boolean getFlag() {
return flag;
}
public void setName(String name) {
this.name = name+num;
num++;
}
public String getName() {
return name;
}
/*对外开放能获取资源对象的方法*/
public static Resource getInstance() {
return r;
}
/*对外开放能获取Lock对象的方法*/
public static Lock getLock() {
return lock;
}
/*对外开放能获取Con1对象的方法*/
public static Condition getCon1() {
return con1;
}
/*对外开放能获取Con2对象的方法*/
public static Condition getCon2() {
return con2;
}
}
package compro;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
/**
* 生产类(生产一般是多个,所以用线程
属性:资源的对象引用
行为:生产
*/
public class Producer implements Runnable {
private Resource r = Resource.getInstance(); //资源
private Lock lock = Resource.getLock(); //锁
private Condition con1 = Resource.getCon1(); //监视器
/* 生产 */
public void set(String name) {
r.setName("商品");
System.out.println(Thread.currentThread().getName() + " : 生产 " + r.getName());
}
@Override
public void run() {
// TODO Auto-generated method stub
lock.lock();
try {
while (true) {
while (r.getFlag()) {
try {
con1.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
set("商品");
r.setFlag(true);
con1.signal();
}
} finally {
// TODO: handle finally clause
lock.unlock();
}
}
}
package compro;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
/**
* 消费类(消费一般是多个,所以用线程)
* 属性:资源的对象引用
* 行为:消费
* */
public class Consumer implements Runnable{
private Resource r=Resource.getInstance(); //资源
private Lock lock=Resource.getLock(); //锁
private Condition con2=Resource.getCon2(); //监视器
/*消费*/
public void out() {
System.out.println(Thread.currentThread().getName()+" : 消费 "+r.getName());
}
@Override
public void run() {
// TODO Auto-generated method stub
lock.lock();
try {
while(true) {
while(!r.getFlag()) {
try {
con2.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
out();
r.setFlag(false);
con2.signal();
}
} finally {
// TODO: handle finally clause
lock.unlock();
}
}
}
package compro;
/**
* 测试类
* */
public class Demo {
public static void main(String[] args) {
Producer p=new Producer(); //实例化生产
Consumer c=new Consumer(); //实例化消费
Thread t1=new Thread(p);
Thread t2=new Thread(p);
Thread t3=new Thread(c);
Thread t4=new Thread(c);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
Synchronized代码块的锁,是对象的锁。每个对象都会有一个隐式的锁。会自动的开启和关闭。
而Lock,需要显式的进行开启和关闭是,并且关闭是必须的,不然不关闭的话,就会占用资源。所以利用try/finally的组合,无论怎么样都要关闭。
Condition的作用是则是监视器,利用await()和signal()代替了Object中的wait()和notify()。