关于Java同步锁中await和signalAll的使用经验

来源:互联网 发布:淘宝吉他店铺推荐 编辑:程序博客网 时间:2024/05/16 19:30

当使用Lock来保证线程同步时,需使用Condition对象来使线程保持协调。Condition实例被绑定在一个Lock的对象上,使用Lock对象的方法newCondition()获取Condition的实例。Condition提供了下面三种方法,来协调不同线程的同步:

1、await():导致当前线程等待,直到其他线程调用该Condition的signal()或signalAll()方法唤醒该线程。

2、signal():唤醒在此Lock对象上等待的单个线程。

3、signalAll():唤醒在此Lock对象上等待的所有线程。

我在进行《疯狂Java讲义(精粹)第二版》多线程一章的一道习题的编程时遇到了使用了await()和signalAll()进行线程同步,却导致了死锁的问题。在网络搜寻了下,原因是我对await()方法理解有误导致。题目如下:写2个线程,其中一个线程打印1-52,另一个线程打印A-Z,打印顺序应该是12A34B56C……5152Z,需使用多线程通信的知识解决。

附上最终正确运行的代码,同时加上了开始时犯的错误的注释。

1、PrintTask

import java.util.ArrayList;import java.util.Iterator;import java.util.List;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class PrintTask<T> implements Runnable {private List<T> charList = new ArrayList<>();//需打印的队列。由于打印项目既包含字符也包含递增的数字,此处使用泛型private int period;//每次打印的个数private int priority;//优先级,即在多个队列中的打印次序private int total;//打印队列总数public static int sequence = 0;//当前打印的队列序号private static final Lock lock = new ReentrantLock();//由于需要锁定的sequence是类成员,创建一个static锁,保证该类不同线程实例能够感知到signalAll()private static final Condition condition = lock.newCondition();//类Condition成员//private final Lock lock = new ReentrantLock();----------->当不使用static定义Lock和Condition时,由于不同线程为不同的实例,相互之间//private final Condition condition = lock.newCondition();无法感知其他类发出的signalAll(),导致线程之间相互等待却无法得到响应public PrintTask(List<T> charList, int period, int priority, int total) {this.charList = charList;this.period = period;this.priority = priority;this.total = total;}public void run() {Iterator<T> iter = charList.iterator();while(true) {lock.lock();//锁定try {if (sequence % total == priority) {for (int i = 0; i < period; i++) {if(iter.hasNext()) {System.out.print(iter.next());}else {break;}}++sequence;condition.signalAll();//该类其他实例均能接受到该signalAll()方法}else {condition.await();//类成员condition的await()方法,告知类的所有实例均感知signalAll()}}catch (Exception ex) {ex.printStackTrace();}finally {lock.unlock();}}}}

2、主程序PrintAZ.java

import java.util.ArrayList;import java.util.List;public class PrintAZ {final static int TOTAL = 2;public static void main(String[] args) {//生成数字列表1-52List<Integer> numbers = new ArrayList<>();for (int i = 1; i <= 52; i++) {numbers.add(i);}//生成字母列表A-ZList<Character> chars = new ArrayList<>();for (char i = 'A'; i <= 'Z'; i++){chars.add(i);}//PrintTask(打印队列, 每次打印长度, 次序, 队列总数) PrintTask<Integer> task1 = new PrintTask<>(numbers, 2, 0, TOTAL);PrintTask<Character> task2 = new PrintTask<>(chars, 1, 1, TOTAL);new Thread(task1).start();new Thread(task2).start();}}

当定义Lock和Condition为实例成员变量时,运行结果如下:

12A
Lock和Condition为类成员时,运行结果如下:

12A34B56C78D910E1112F1314G1516H1718I1920J2122K2324L2526M2728N2930O3132P3334Q3536R3738S3940T4142U4344V4546W4748X4950Y5152Z


0 0
原创粉丝点击