java Condition 学习

文章描述了一个Java编程中使用ReentrantLock和Condition控制线程交替打印数字和字母的问题。作者首先遇到线程无法唤醒的问题,原因是每个线程有自己的Condition实例,导致无法相互唤醒。修正后,线程能交替进行,但主线程在子线程完成后未继续执行,原来是await()导致的无限等待。最后,通过设置await()的超时解决了这个问题,确保程序正常运行并结束。
摘要由CSDN通过智能技术生成

平时用Condition 少,最近来学一下,利用Condition 交替打印 数字和字母 1a2b3c, 一直有问题,找了资料看,也没搞明白自己的问题,去问答里面问人,也没人鸟。今晚捣鼓出来了,写一下遇到的问题和解决。以下代码是 遇到锁,唤醒不了,一直等待。 叫版A吧

public class LockAndCondition {
@Test
public void t1() throws InterruptedException {
Lock lock = new ReentrantLock();
Masthead m1 = new Masthead(new Object[]{1, 2, 3}, lock, "T1");
Masthead m2 = new Masthead(new Object[]{"A", "B", "C"}, lock, "T2");
m1.start();
Thread.sleep(1000);
m2.start();
m1.join();
m2.join();
}

}

class Masthead extends Thread {
Object[] data;
Lock lock;
Condition condition;
String name;

public Masthead(Object[] data, Lock lock, String name) {
    this.data = data;
    this.lock = lock;
    this.condition = lock.newCondition();
    this.name = name;
    setName(name);
}
 
 
@Override
public void run() {
    try {
        lock.lock();
        for (Object d : data) {
            System.out.println(d);
            condition.signalAll();
            condition.await();
        }
        condition.signalAll();
    } catch (InterruptedException e) {
        e.printStackTrace();
    } finally {
        lock.unlock();
    }
}
}

只会打印出 1A,就一直无限等待了,按我的理解,应该是在等待之前再唤醒另一个线程工作,怎么都在等待。 看了快照 说 java.lang.Thread.State: WAITING (on object monitor),就是等待被唤醒,那奇怪了,condition.signalAll(); 没起效吗? 找了挺多资料看,也没搞懂。后面发现,lock是同一把锁了,但是 条件condition 不是,  线程里的都是 new出来的, 

this.condition = lock.newCondition();

所以,同一把锁,不同条件condition, 唤醒不了不同的 condition 等待对象,哎 到这里 终于也好了

修改好,版B

public class LockAndCondition {
    @Test
    public void t1() throws InterruptedException {
        Lock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        Masthead m1 = new Masthead(new Object[]{1, 2, 3}, lock, condition, "T1");
        Masthead m2 = new Masthead(new Object[]{"A", "B", "C"}, lock, condition, "T2");
        m1.start();
        Thread.sleep(1000);
        m2.start();
        m1.join();
        m2.join();
    }

}

class Masthead extends Thread {
    Object[] data;
    Condition condition;
    String name;
    Lock lock;

    public Masthead(Object[] data, Lock lock, Condition condition, String name) {
        this.data = data;
        this.condition = condition;
        this.name = name;
        this.lock = lock;
        setName(name);
    }


    @Override
    public void run() {
        for (Object d : data) {
            lock.lock();
            System.out.println(d);
            condition.signalAll();
            try {
                condition.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }
}

这时,可以打印出   1A2B3C    ,但是 又发现新的问题,按理说,我线程内容都执行完了,为什么,主线程没继续往下走,卡着了?  jstack 一下, 又是 java.lang.Thread.State: WAITING (on object monitor), 又在等待唤醒? 主线程还要唤醒? 不是join的吗? 子线程完了 主线程就可以继续走了的

看了几遍,难不成, await() 有问题? 还是说没解锁?

猜想验证

public class LockAndCondition {
    @Test
    public void t1() throws InterruptedException {
        Lock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        Masthead m1 = new Masthead(new Object[]{1, 2, 3}, lock, condition, "T1");
        Masthead m2 = new Masthead(new Object[]{"A", "B", "C"}, lock, condition, "T2");
        m1.start();
        Thread.sleep(1000);
        m2.start();
        m1.join();
        m2.join();
    }

}

class Masthead extends Thread {
    Object[] data;
    Condition condition;
    String name;
    Lock lock;

    public Masthead(Object[] data, Lock lock, Condition condition, String name) {
        this.data = data;
        this.condition = condition;
        this.name = name;
        this.lock = lock;
        setName(name);
    }


    @Override
    public void run() {
        for (Object d : data) {
            lock.lock();
            System.out.println(d);
            condition.signalAll();
            try {
                condition.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
                System.out.println("解锁"+d);
            }
        }
    }
}

1
A
解锁1
2
解锁A
B
解锁2
3
解锁B
C
解锁3

到了,C这里, 没解锁。也就是 打印了c之后, await(),没有被唤醒,无限等待了。另一个线程早就执行完退出了,不可能再来唤醒,对题目来说也不对。那么 按照打破锁的 军规,就当前情况就该有个超时解锁,那么 await(时间)

public class LockAndCondition {
    @Test
    public void t1() throws InterruptedException {
        Lock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        Masthead m1 = new Masthead(new Object[]{1, 2, 3}, lock, condition, "T1");
        Masthead m2 = new Masthead(new Object[]{"A", "B", "C"}, lock, condition, "T2");
        m1.start();
        Thread.sleep(1000);
        m2.start();
        m1.join();
        m2.join();
    }

}

class Masthead extends Thread {
    Object[] data;
    Condition condition;
    String name;
    Lock lock;

    public Masthead(Object[] data, Lock lock, Condition condition, String name) {
        this.data = data;
        this.condition = condition;
        this.name = name;
        this.lock = lock;
        setName(name);
    }


    @Override
    public void run() {
        for (Object d : data) {
            lock.lock();
            System.out.println(d);
            condition.signalAll();
            try {
                condition.await(2,TimeUnit.SECONDS);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
                System.out.println("解锁"+d);
            }
        }
    }
}

1
A
解锁1
2
解锁A
B
解锁2
3
解锁B
C
解锁3
解锁C

这时 ,按顺序打印了,执行完,也正常退出,没有卡住主线程。 OK 打完收工

看完不动手等于白学,领会到了T_T


                
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值