线程在具体使用中还会使用一些辅助类,现在就聊一些常用辅助类如何使用。
CountDownLatch
看一下官网的解释:
可以看出CountDownLatch类可以设置一个计数器,而后调用countDown方法进行减1操作,然后使用await方法等待计数器等于0,然后继续指向await方法之后的语句。
还是老规矩演示:
public class test {
public static void main(String[] args) {
for (int i = 0; i < 6; i++) {
new Thread(()->{
System.out.println("线程的名字:"+ Thread.currentThread().getName());
},String.valueOf(i)).start();
}
System.out.println("main 线程----------------");
}
}
然后使用CountDownLatch后:
public class test {
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 0; i < 6; i++) {
new Thread(() -> {
System.out.println("线程的名字:" + Thread.currentThread().getName());
countDownLatch.countDown();
}, String.valueOf(i)).start();
}
countDownLatch.await();
System.out.println("main 线程----------------");
}
}
CyclicBarrier
还是老规矩先看官网文档:
CyclicBarrier英语的的意思是循环阻塞,其本质是在CyclicBarrier构造方法中设置一个参数,也就是目标障碍数,每次执行的时候障碍数回加一,如果障碍数达到了才会执行CyclicBarrier.await()之后的。
其实看代码的话构造方法有两个,所以依次演示。
还是老规矩代码演示:
public class test {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(6);
for (int i = 0; i < 6; i++) {
new Thread(() -> {
System.out.println("线程的名字:" + Thread.currentThread().getName());
try {
cyclicBarrier.await();
} catch (Exception e) {
throw new RuntimeException(e);
}
}, String.valueOf(i)).start();
}
System.out.println("main 线程----------------");
}
}
似乎没有什么用,一般的时候使用的构造方法两个参数的:
public class test {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(6,()->{
System.out.println("main 线程----------------");
});
for (int i = 0; i < 6; i++) {
new Thread(() -> {
System.out.println("线程的名字:" + Thread.currentThread().getName());
try {
cyclicBarrier.await();
} catch (Exception e) {
throw new RuntimeException(e);
}
}, String.valueOf(i)).start();
}
}
}
补充与 CountDownLach的区别
如果只是简单的这样,两者似乎功能有些重叠了,如下尝试:
public class test {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(6,()->{
System.out.println("main 线程----------------");
});
for (int i = 0; i < 12; i++) {
new Thread(() -> {
System.out.println("线程的名字:" + Thread.currentThread().getName());
try {
cyclicBarrier.await();
} catch (Exception e) {
throw new RuntimeException(e);
}
}, String.valueOf(i)).start();
}
}
}
然后再
ic class test {
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 0; i < 12; i++) {
new Thread(() -> {
System.out.println("线程的名字:" + Thread.currentThread().getName());
countDownLatch.countDown();
}, String.valueOf(i)).start();
}
countDownLatch.await();
System.out.println("main 线程----------------");
}
}
总结:
- 可以看出CountDownLatch和CyclicBarrier无论是再计数时候是加一还是减一,都有一点那就是需要满足构造的函数才会触发等待后面的程序。
注意一点:因为放开后面的运行其也是多线程格式,如例子那样的演示,并不是6个线程之后一定调用输出main,所以后面的运行和循环线程超过参数的线程也是就在竞争关系。 - CountDownLatch和CyclicBarrier,最大一个区别等待的线程CountDownLatch只是调用了依次,也就是记录的数字归0之后就运行输出main而CountDownLatch就等于失效了,而CyclicBarrier却是一个满足6之后清零,然后再循环满足6次就会调用输出一次main。是循环满足条件后调用后面的程序。
Semaphore
看一下官网:
这个和上面的又有点不同,其本质就是允许同时允许的线程数量是多少,然后运行完毕之后再回运行新的线程,还是老规矩进行代码演示:
public class test {
public static void main(String[] args) {
// 印度阿三网吧就有三台机子
Semaphore semaphore=new Semaphore(3);
// 今天一共9个顾客
for (int i = 0; i < 9; i++) {
new Thread(()->{
try {
// 网管电脑显示机子被用加一
semaphore.acquire();
System.out.println("第【"+Thread.currentThread().getName()+"】顾客充值上机了");
// 来一个延迟不然显示结果不太明显
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}finally {
System.out.println("第【"+Thread.currentThread().getName()+"】顾客被老妈带着拖鞋捏着耳朵叫回家了");
// 网管电脑显示机子被用减一
semaphore.release();
}
},String.valueOf(i)).start();
}
}
}
可以看出每次执行的线程数量保持为3个,也就是Semaphore规定的数量。所以有时候为了防止多线程占性能,毕竟多了有时候性能会更低所以需要通过这个进行控制线程数量来尽可能的提高性能。