1.1 Semaphore的使用
此类的主要作用就是限制线程并发的数量,如果不限制线程并发的数量,则CPU的资源很快就被耗尽,每个线程执行的任务是相当缓慢。
Semaphore类发放许可的计算方式是“减去”操作。
1.1.1 Semaphore的同步性
private Semaphore semaphore = new Semaphore(2);
类Semaphore的构造函数参数permits是许可的意思,代表同一时间内,最多允许多少个线程同时执行acquire()和release()之间的代码。
无参方法acquire()的作用是使用一个许可,是减法操作。
1.1.2 Semaphore构造方法permits参数作用
private Semaphore semaphore = new Semaphore(int permits);
表示同一时间内最多有permits个线程执行 acquire()和release()之间的代码。
注意:对Semaphore类的构造方法传递的参数permits值如果大于1时,该类并不能保证线程安全性,因为还是有可能会出现多个线程共同访问实例变量,导致出现脏数据的情况。
1.1.3 方法acquire(int permits)参数作用及动态添加permits许可数量
private Semaphore semaphore = new Semaphore(10);//10并不是最终的许可数量,
// 仅仅是初始的状态值
semaphore.acquire(int permits);//获得permits个许可
semaphore.release(int permits);//释放permits个许可
1.1.4 方法acquireUninterruptibly()的使用
方法acquireUninterruptibly()的作用是使等待进入acquire()方法的线程,不允许被中断。
1.1.5 方法availablePermits()和drainPermits()
availablePermits()返回此Semaphore对象中当前可用的许可数。
drainPremits() 获取并返回立即可用的所有许可个数,并且将可用许可置0。
1.1.6 方法getQueueLength()和hasQueuedThreads()
getQueueLength() 获得等待许可的线程个数
hasQueuedThreads()判断有没有线程在等待这个许可
1.1.7 公平与非公平信号量
private Semaphore semaphore = new Semaphore(int permits,boolean fair) fair设置是否为公平信号量,默认为false
1.1.8 方法tryAcquire()的使用
无参方法tryAcquire() 的作用是尝试地获得一个许可,如果获取不到则返回false,此方法通常与if语句结合使用,其具有无阻塞的特点。无阻塞的特点可以使线程不至于在同步处一直持续等待的状态,如果if语句判断不成立则线程会继续走else语句,程序会继续向下执行。
方法tryAcquire(int permits) 尝试地获得x个许可,如果获取不到则返回false
方法tryAcquire(long timeout,TimeUnit unit) 在指定的时间内尝试地获得1个许可,如果获取不到则返回false
方法tryAcquire(int permits,long timeout,TimeUnit unit) 在指定的时间内尝试获取x个许可,如果获取不到返回false
1.1.9 多进路-多处理-多出路实验
本实现的目标是允许多个线程同时处理任务,更具体来讲,也就是每个线程都在处理自己的任务。
public class Service{
private Semaphore semaphore = new Semaphore(3);
public void say(){
semaphore.acquire();
..................
semaphore.release();
}
}
1.1.10 多进路-单处理-多出路实验
本实现的目标是允许多个线程同时处理的任务,但执行任务的顺序却是同步的,也就是阻塞的,所以也称单处理。
public class Service{
private Semaphore semaphore = new Semaphore(3);
private ReentrantLock lock = new ReentrantLock();
semaphore.acquire();
lock.lock();
..................
lock.unlock();
semaphore.release();
}
1.1.11 使用Semaphore创建字符串池
实验代码
1.1.12 使用Semaphore实现多生产者/多消费者模式
实验代码
类Semaphore提供了限制并发线程数的功能,此功能在默认的synchronized中是不提供的。
类Exchanger的功能可以使2个线程之间传输数据,它比生产者/消费者模式使用的wait/notify要更加方便
2.1 方法exchange()阻塞的特性
类Exchanger中的exchange()方法具有阻塞的特色,也就是此方法被调用后等待其他线程来取得数据,如果没有其他线程取得数据,则一直阻塞等待。
package cn.yu.Exchanger;
import java.util.concurrent.Exchanger;
public class ThreadA extends Thread {
private Exchanger<String> exchanger;
public ThreadA(Exchanger<String> exchanger) {
super();
this.exchanger = exchanger;
}
public void run() {
try {
System.out.println("在线程A中得到线程B的值:"+exchanger.exchange("我是线程A发送给线程B的值"));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package cn.yu.Exchanger;
import java.util.concurrent.Exchanger;
public class ThreadB extends Thread {
private Exchanger<String> exchanger;
public ThreadB(Exchanger<String> exchanger) {
super();
this.exchanger = exchanger;
}
public void run() {
try {
System.out.println("在线程B中得到线程A的值:"+exchanger.exchange("我是线程B发送给线程A的值"));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package cn.yu.Exchanger;
import java.util.concurrent.Exchanger;
public class Test {
public static void main(String[] args) {
Exchanger<String> exchanger = new Exchanger<String>();
ThreadA a = new ThreadA(exchanger);
ThreadB b = new ThreadB(exchanger);
a.start();
b.start();
}
}
运行结果:
在线程B中得到线程A的值:我是线程A发送给线程B的值
在线程A中得到线程B的值:我是线程B发送给线程A的值
2.2 方法exchange(V v,long timeout,TimeUnit unit)阻塞的特性
当调用exchange(V x,long timeout,TimeUnit unit)方法后在指定的时间内没有其他线程获取数据,则出现超时异常。
本章总结:
类Semaphore的主要作用是限制并发执行的线程个数,它具有synchronized所不具有的强大功能,比如等待获得许可的同时可以加入等待时间,还有尝试是否可以持有锁等这类扩展功能。
Exchanger是线程间传输数据的方式之一,而且在传输的数据类型上并没有任何限制。