如何保证多个线程同时执行
CountDownLatch是一个计数器闭锁,主要的功能就是通过await()方法来阻塞住当前线程,然后等待计数器减少到0了,向下减计数器的方法:countdown()。
public class Demo1 {
public static void main(String[] args) {
int threadCount = 3;
//计数器设置为1
CountDownLatch countDownLatch = new CountDownLatch(1);
for (int i = 0; i < threadCount; i++) {
new Thread(() -> {
try {
//阻塞
countDownLatch.await();
System.out.println(Thread.currentThread().getName() + "线程开始时间:" + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
System.out.println("计数器减一,变成0,开始执行三个子线程");
countDownLatch.countDown();
try {
Thread.sleep(5000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("主线程执行结束");
}
}
执行结果如下:
可以看到三个线程开始时间一直(可能会有纳米级的误差)。
如何保证多个线程在并发下依次执行
使用volatile 和 static来标记一个变量,实现demo如下:
public class Demo2 {
private volatile static int flag = 1;
public static void main(String[] args) {
Thread th1 = new Thread(() -> {
while (true) {
if (flag == 1) {
try {
// Thread.sleep(1000L);
System.out.println("执行线程" + Thread.currentThread().getName() + "业务");
} catch (Exception e) {
e.printStackTrace();
}
flag = 2;
return;
}
}
});
Thread th2 = new Thread(() -> {
while (true) {
if (flag == 2) {
try {
// Thread.sleep(1000L);
System.out.println("执行线程" + Thread.currentThread().getName() + "业务");
} catch (Exception e) {
e.printStackTrace();
}
flag = 3;
return;
}
}
});
Thread th3 = new Thread(() -> {
while (true) {
if (flag == 3) {
try {
// Thread.sleep(1000L);
System.out.println("执行线程" + Thread.currentThread().getName() + "业务");
} catch (Exception e) {
e.printStackTrace();
}
flag = 1;
return;
}
}
});
th1.start();
th2.start();
th3.start();
}
}
结果如下:
这里flag必须要用volatile修饰
如何保证多个线程有序交错执行
使用Semaphore 类;
public class Demo3 {
//设置信号量为1
private static Semaphore semaphore1 = new Semaphore(1);
private static Semaphore semaphore2 = new Semaphore(1);
private static Semaphore semaphore3 = new Semaphore(1);
public static void main(String[] args) {
int size = 10;
try {
//获取信号量,当被获取后不释放将会卡住
semaphore2.acquire();
semaphore3.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread th1 = new Thread(() -> {
for (int i = 0; i < size; i++) {
try {
//第一次进来由于2和3被获取了,其他线程被卡住,所以这里能获取到
semaphore1.acquire();
System.out.println("执行线程" + Thread.currentThread().getName() + "业务");
} catch (Exception e) {
e.printStackTrace();
}
//释放第二个信号量
semaphore2.release();
}
});
Thread th2 = new Thread(() -> {
for (int i = 0; i < size; i++) {
try {
semaphore2.acquire();
System.out.println("执行线程" + Thread.currentThread().getName() + "业务");
} catch (Exception e) {
e.printStackTrace();
}
semaphore3.release();
}
});
Thread th3 = new Thread(() -> {
for (int i = 0; i < size; i++) {
try {
semaphore3.acquire();
System.out.println("执行线程" + Thread.currentThread().getName() + "业务");
} catch (Exception e) {
e.printStackTrace();
}
semaphore1.release();
}
});
th1.start();
th2.start();
th3.start();
}
}
结果可看到几个线程是依次轮询执行:
Semaphore并不控制线程之间的关系;它表示的是一个可使用资源的数目,如上new Semaphore(1),则表示创建资源数为1,当调用acquire()方法后,资源数为0,当有其他线程再次调用acquire()时,因为这时没有资源了,所以这里会卡住住,等到调用release()方法后,归还资源,其他线程才会去执行。它也被更多地用来限制流量,类似阀门的功能。