今天就跟大家聊聊有关Java中如何实现线程通信,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。
1、synchronized加wait/notify方式
/**
* wait和notify的使用
* wait和notify必须应用在synchronized块或方法内
* 下面的代码向跳交谊舞一样互相控制着对方的输出
*/
public class MutiThread_WaitNotify {
public static void main(String[] args) {
final Object lock = new Object();
Thread a = new Thread(new Runnable(){
@Override
public void run(){
synchronized (lock){
try{
lock.wait();
System.out.println("A-1");
lock.notify();
lock.wait();
System.out.println("A-2");
lock.notify();
lock.wait();
System.out.println("A-3");
lock.notify();
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
});
Thread b = new Thread(new Runnable(){
@Override
public void run(){
synchronized (lock){
try{
System.out.println("B-1");
lock.notify();
lock.wait();
System.out.println("B-2");
lock.notify();
lock.wait();
System.out.println("B-3");
lock.notify();
lock.wait();
System.out.println("B-4");
}catch(InterruptedException e){
e.printStackTrace();;
}
}
}
});
a.start();
b.start();
}
}
2、ReentrantLock加Condition方式
/**
* ReentrantLock和Condition的使用
* 在使用Conditioin的await和signal时,必须将这两个方法写在ReentrantLock的lock方法之后
*/
public class MutiThread_ReentrantLock_Condition {
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
int i=1;
for(; i<=6; i++){
final int k = i;
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try{
lock.lock();
System.out.println("ThreadNo:A" + k + " is locked");
// 通过condition.await将线程阻塞
condition.await();
}catch(InterruptedException e){
e.printStackTrace();
}finally{
lock.unlock();
System.out.println("ThreadNo:A"+k + " is unlocked");
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
if(k == 6){
try{
lock.lock();
System.out.println("All Threads is signaled");
// 通过condition.signalAll唤醒所有线程
condition.signalAll();
}catch(Exception e){
e.printStackTrace();
}finally{
lock.unlock();
}
}else{
System.out.println("threads can't signaled, wait a moment.");
}
}
});
t1.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
}
}
}
3、闭锁方式
import java.util.concurrent.CountDownLatch;
/**
* 闭锁的使用
* 闭锁用于等待事件,当闭锁到达结束状态(本例中是闭锁的计数器值减为0)之前,所有线程都等待,当闭锁到达结束状态时,所有线程都通过
* 闭锁是一次性的,当闭锁到达结束状态后,将不会被重置,这个锁会永远打开并允许所有线程通过。
* 可以将代码中的NUM变量值变为2和4,分别试试什么效果
*/
public class MutiThread_CountDownLatch {
public static void main(String[] args) {
// 定义闭锁,并设置闭锁的计数器值为3
CountDownLatch lock = new CountDownLatch(3);
// 循环定义3个线程
int NUM = 3;
for(int i=1; i<=NUM; i++){
final int k = i;
Thread a = new Thread(new Runnable(){
@Override
public void run(){
try{
Thread.sleep(k * 1000);
System.out.println("ThreadNo:A"+k);
// 每个线程在休眠指定时间后将闭锁的计数器值减1,当闭锁的计数器值减到0时,闭所将被打开,从而使第二个循环中的所有线程才能通过
lock.countDown();
// 打印闭锁计数器的值
System.out.println("ThreadNo:A"+k+"; getCount:"+lock.getCount());
}catch(InterruptedException e){
e.printStackTrace();
}
}
});
a.start();
}
// 循环定义2个线程
for(int i=1; i<=2; i++){
final int k = i;
Thread b = new Thread(new Runnable(){
@Override
public void run(){
try{
System.out.println("ThreadNo:B"+k+" is waiting...");
// 当闭锁的计数器值不为0时,线程将在此处被中断
lock.await();
// 当闭锁的计数器值等于0时,闭锁将被打开,所有等待的线程都将被唤醒
System.out.println("ThreadNo:B"+k+" is notify");
}catch(InterruptedException e){
e.printStackTrace();
}
}
});
b.start();
}
}
}
4、栅栏的方式
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
* 栅栏的使用
* 栅栏用于等待线程,所有线程必须同时到达栅栏,才能继续执行
* 栅栏不是一次性的,可以被重置。
* 可以将代码中的NUM变量值变为5和7,分别试试什么效果
*/
public class MutiThread_CyclicBarrier {
public static void main(String[] args) {
// 定义栅栏,并设置栅栏需要等待的线程数为6
CyclicBarrier barrier = new CyclicBarrier(6);
int NUM = 100;
for(int i=1; i<=NUM; i++){
final int k = i;
Thread t = new Thread(new Runnable() {
@Override
public void run() {
try{
Thread.sleep(k * 1000);
System.out.println("ThreadNo:"+k+" is waiting, getNumberWaiting:" + barrier.getNumberWaiting());
// 栅栏设置的等待线程数为6,当线程数不够6个时,所有线程将在此等待
barrier.await();
// 当线程数达到6个时,栅栏将被打开,所有线程都将被唤醒
System.out.println("ThreadNo:"+k+" is notify");
// 栅栏被重置,以便下次继续使用
barrier.reset();
}catch(InterruptedException e){
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
});
t.start();
}
}
}
5、信号量的方式
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Semaphore;
/**
* 信号量的使用
* 信号量用于控制同时访问某个资源的线程数量,信号量还可以用于实现某个资源池。
* 信号量管理者一组虚拟的许可,线程在执行操作时首先要获得许可,如果信号量的许可数量为0,那么accquire将阻塞直到有许可为止
* 信号量不是一次性的,当信号链的许可用完之后,可以通过release释放许可
*/
public class MutiThread_Semaphore {
public static void main(String[] args) {
// 定义信号量,并设置信号量的允许发放的最大许可数量为6
final Semaphore semaphore = new Semaphore(6);
// 定义集合,当信号量未发放的许可数量大于0则允许线程向集合内添加元素
final List<String> set = new ArrayList<>();
int i = 1;
while(true){
final int k = i++;
Thread t = new Thread(new Runnable() {
@Override
public void run() {
boolean res = false;
try{
System.out.println("ThreadNo:A"+k+", availablePermits:"+semaphore.availablePermits());
// 当信号量允许发放的许可数量大于0,则会向集合内添加元素,否则将被中断于此
semaphore.acquire();
res = set.add("1");
System.out.println("ThreadNo:A"+k+" add item success");
}catch(InterruptedException e){
e.printStackTrace();
}finally{
if(!res){
semaphore.release();
}
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
if(semaphore.availablePermits() == 0){
// 如果信号量允许发放的许可数量等于0,则释放制定数量的许可
semaphore.release(3); //释放3个许可
System.out.println("ThreadNo:B"+k+" releasePermitNum:"+semaphore.availablePermits());
}
}
});
t.start();
t2.start();
System.out.println("the num of set:"+set.size());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
A、join的使用
/**
* join的使用
* 实现当调用join的线程执行完毕后,其他线程才能执行
*/
public class MutiThread_Join {
public static void main(String[] args) {
Thread a = new Thread(new Runnable(){
@Override
public void run(){
printNumber("A");
}
});
Thread b = new Thread(new Runnable(){
@Override
public void run(){
printNumber("B");
}
});
try{
a.start();
// a线程执行完毕后,b线程才能执行
a.join();
b.start();
}catch(InterruptedException e){
e.printStackTrace();;
}
}
public static void printNumber(String s){
System.out.println(s+" print:"+s);
}
}
B、yield的使用
/**
* yield,当一个线程中调用了这个方法后,这个线程就会把自己的CPU执行时间让给自己或其它线程,
* 注意是让给自己或其它线程,并不是单纯让给其他线程。yield执行后,能让当前线程由运行状态
* 进入到就绪状态,将自己的CPU时间片让出来,让出来之后有可能是其它线程执行,也有可能是该线程
* 继续执行。优先级高的线程并不一定是首先执行,而是首先执行的概率会高一些。优先级在大量线程
* 执行的时候才能体现的出来。
*/
public class MutiThread_yield {
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
for(int i=0;i<10;i++){
System.out.println("ThreadNo:A"+i);
Thread.yield();
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
for(int i=0;i<10;i++){
System.out.println("ThreadNo:B"+i);
Thread.yield();
}
}
});
t1.setPriority(Thread.MIN_PRIORITY);
t2.setPriority(Thread.MAX_PRIORITY);
t1.start();
t2.start();
}
}
看完上述内容,你们对Java中如何实现线程通信有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注亿速云行业资讯频道,感谢大家的支持。
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
原文链接:https://my.oschina.net/u/3272058/blog/3068524