线程的同步
多线程对同步资源的访问有可能导致数据的不一致性,所以需要确保共享资源在某个时段只能被同一个线程访问。
1.互斥锁
synchronized用在对象前面限制一段代码的执行
用在方法声明中,表示方法是同步方法
public class MyStack {
int idx = 0;
char[] data = new char[6];
public void push(char c){
synchronized(this){
data[idx++] = c;
}
}
public synchronized char pop(){
return data[--idx];
}
}
/*这个小程序模拟的是线程死锁的问题*/
public class TestDeadLock implements Runnable {
public int flag = 1;
static Object o1 = new Object(), o2 = new Object();
public void run() {
System.out.println(Thread.currentThread().getName() + "的flag=" + flag);
/*
* 运行程序后发现程序执行到这里打印出flag以后就再也不往下执行后面的if语句了
* 程序也就死在了这里,既不往下执行也不退出
*/
/* 这是flag=1这个线程 */
if (flag == 1) {
synchronized (o1) {
/* 使用synchronized关键字把对象01锁定了 */
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o2) {
/*
* 前面已经锁住了对象o1,只要再能锁住o2,那么就能执行打印出1的操作了
* 可是这里无法锁定对象o2,因为在另外一个flag=0这个线程里面已经把对象o1给锁住了
* 尽管锁住o2这个对象的线程会每隔500毫秒睡眠一次,可是在睡眠的时候仍然是锁住o2不放的
*/
System.out.println("1");
}
}
}
/*
* 这里的两个if语句都将无法执行,因为已经造成了线程死锁的问题
* flag=1这个线程在等待flag=0这个线程把对象o2的锁解开,
* 而flag=0这个线程也在等待flag=1这个线程把对象o1的锁解开
* 然而这两个线程都不愿意解开锁住的对象,所以就造成了线程死锁的问题
*/
/* 这是flag=0这个线程 */
if (flag == 0) {
synchronized (o2) {
/* 这里先使用synchronized锁住对象o2 */
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o1) {
/*
* 前面已经锁住了对象o2,只要再能锁住o1,那么就能执行打印出0的操作了 可是这里无法锁定对象o1,因为在另外一个flag=1这个线程里面已经把对象o1给锁住了 尽管锁住o1这个对象的线程会每隔500毫秒睡眠一次,可是在睡眠的时候仍然是锁住o1不放的
*/
System.out.println("0");
}
}
}
}
public static void main(String args[]) {
TestDeadLock td1 = new TestDeadLock();
TestDeadLock td2 = new TestDeadLock();
td1.flag = 1;
td2.flag = 0;
Thread t1 = new Thread(td1);
Thread t2 = new Thread(td2);
t1.setName("线程td1");
t2.setName("线程td2");
t1.start();
t2.start();
}
}
3.线程同步通讯:生产者消费者问题
同步方法中,被锁定的对象可以调用wait()方法,将导致当前线程被阻塞并释放该对象的互斥锁,其他线程有机会访问该对象。
调用了wait()方法的线程将被加入一个特殊的对象等待序列中,直到调用了该wait()方法的对象在其他线程中调用了notify()或notifyAll()方法,或是经理了约定的等待时间,等待才解除。
public class Godown {
public static final int max_size = 100;//最大库存
public int curnum;
Godown(){
}
Godown(int curnum){
this.curnum = curnum;
}
public synchronized void produce(int neednum){
while(neednum+curnum>max_size){
System.out.println("超过库存");
try {
//当前的生产线程等待
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//满足条件则生产
curnum += neednum;
System.out.println("已经生产了" + neednum + "个产品,现仓储量为" + curnum);
//唤醒在此对象监视器上等待所有线程
notifyAll();
}
public synchronized void consume(int neednum){
while(curnum<neednum){
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
curnum -= neednum;
System.out.println("已经消费了" + neednum + "个产品,现仓 储量为" + curnum);
notifyAll();
}
}
class Producer extends Thread{
private final int neednum;
private final Godown godown;
Producer(int neednum, Godown godown){
this.neednum = neednum;
this.godown = godown;
}
public void run(){
godown.produce(neednum);
}
}
class Consumer extends Thread{
private final int neednum;
private final Godown godown;
Consumer(int neednum, Godown godown){
this.neednum = neednum;
this.godown = godown;
}
public void run(){
godown.consume(neednum);
}
}