java线程通信的几种方式_Java实现线程通信的几种方式

雨点打透心脏的1/2处 2022-11-01 15:58 343阅读 0赞

本文共总结了5种方式,通过代码举例的方式进行展示。5种方式为:synchronized加wait/notify方式、ReentrantLock加Condition方式、闭锁的方式、栅栏的方式、信号量的方式。

最后还介绍了join和yield的使用。

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 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();

}

}

发表评论

表情:
评论列表 (有 0 条评论,343人围观)

还没有评论,来说两句吧...

相关阅读