目前有个任务需要对数据进行一个循环处理,那么就需要多线程顺序触发的问题了.
这里以顺序打印为例子对常见的多线程顺序处理做个总结,拿出两个非常常用的方式.
方法一: 资源+锁
核心点:
1.锁共同资源lock
2.通过while循环判断每次被唤醒是否要再次阻塞
public class ThreadsPrintOrder {
private static Integer curr = 0;
private static String[] strs = new String[]{"A", "B", "C"};
private static int count = 10;
static Object lock=new Object();
public static void main(String[] args) {
final Thread a = getThread("A");
final Thread b = getThread("B");
final Thread c = getThread("C");
a.start();
b.start();
c.start();
}
private static Thread getThread(String threadName) {
return new Thread(() -> {
synchronized (lock) {
for (int i = 0; i < count; i++) {
while (!strs[curr%strs.length].equals(threadName)) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName());
curr++;
lock.notifyAll();
}
}
}, threadName);
}
}
方法二 一个ReentrantLock加多个conditon实现(推荐,安全性,性能和可读性较高)
上面那种方法有个缺点就是每个线程被唤醒是随机的,每次被唤醒的可能是我们不想打印的线程,需要它再次自我关闭.
而ReentrantLock的独特效果可以做到结合conditon实现定向唤醒.
public class ThreadsPrintOrder_m2 {
static int count=10;
public static void main(String[] args) {
LockOrderPrint lockOrder=new LockOrderPrint();
new Thread(()->{
for (int i = 0; i <count ; i++) {
lockOrder.printA();
}
}).start();
new Thread(()->{
for (int i = 0; i <count ; i++) {
lockOrder.printB();
}
}).start();
new Thread(()->{
for (int i = 0; i <count ; i++) {
lockOrder.printC();
}
}).start();
}
}
class LockOrderPrint {
int flag=0;
Lock lock=new ReentrantLock();
Condition conditionA=lock.newCondition();
Condition conditionB=lock.newCondition();
Condition conditionC=lock.newCondition();
public void printA(){
lock.lock();
try {
while (flag%3!=0){
try {
conditionA.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("A");
flag++;
conditionB.signal();
}catch (Exception exce){
exce.printStackTrace();
}finally {
lock.unlock();
}
}
public void printB(){
lock.lock();
try {
while (flag%3!=1){
try {
conditionB.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("B");
flag++;
conditionC.signal();
}catch (Exception exce){
exce.printStackTrace();
}finally {
lock.unlock();
}
}
public void printC(){
lock.lock();
try {
while (flag%3!=2){
try {
conditionC.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("C");
flag++;
conditionA.signal();
}catch (Exception exce){
exce.printStackTrace();
}finally {
lock.unlock();
}
}
}
方法三 基于信号量来做
public class ThreeThreadPrintOrder {
static AtomicInteger flag = new AtomicInteger();
//打印次数
public static void main(String[] args) throws InterruptedException {
Semaphore semaphore = new Semaphore(1);
new Thread(() -> {
while (true) {
try {
semaphore.acquire();
if (flag.get() % 3 == 0) {
System.out.println(Thread.currentThread().getName());
flag.incrementAndGet();
}
semaphore.release();
} catch (Exception e) {
e.printStackTrace();
}
}
}, "A").start();
new Thread(() -> {
while (true) {
try {
semaphore.acquire();
if (flag.get() % 3 == 1) {
System.out.println(Thread.currentThread().getName());
flag.incrementAndGet();
}
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "B").start();
new Thread(() -> {
while (true) {
try {
semaphore.acquire();
if (flag.get() % 3 == 2) {
System.out.println(Thread.currentThread().getName());
flag.incrementAndGet();
}
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "C").start();
Thread.currentThread().wait();
}
}
网友评论