信号量
信号量,通俗也被称为信号灯,是在多线程环境下使用的一种设施, 它负责协调各个线程, 以保证它们能够正确、合理的使用公共资源。信号量对可用许可进行计数,并采取相应的行动。拿到信号量许可的线程可以进入代码,否则就等待。
下面提供一个简单的信号控制例子:
public class ThreadTask {
private int prompt = 1;
public synchronized void transfer() {
this.prompt++;
this.notify();
}
public synchronized void operation() throws InterruptedException {
while(this.prompt == 1) wait();
this.prompt--;
}
线程池
线程池主要用来解决线程生命周期开销问题和资源不足问题。通过对多个任务重复使用线程,线程创建的开销就被分摊到了多个任务上了,而且由于在请求到达时线程已经存在,所以消除了线程创建所带来的延迟。当一个服务器接受到大量短小线程的请求时,使用线程池技术是非常合适的,它可以大大减少线程的创建和销毁次数,提高服务器的工作效率。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadTask implements Runnable {
public static void main(String[] args) {
ExecutorService asd = Executors.newFixedThreadPool(5); //创建线程池
asd.submit(new ThreadTask()); //向线程池中添加三个线程
asd.submit(new ThreadTask());
asd.submit(new ThreadTask());
asd.shutdown(); //关闭线程池
}
String s=Thread.currentThread().getName();
for(int i = 0;i < 10;i++){
System.out.println( s+ "当前的值为:" + i);
}
}
Lock接口及重入锁
JDK5中有一个Lock的默认实现:ReentrantLock:也就是重入锁,它的概念是在获得锁后可以重复获得该资源的锁。synchronized关键字是jvm虚拟机的关键字,在java中还有一个Lock接口,和Lock接口的实现类ReentrantLock(可重入锁)。 ReentrantLock可以实现和synchronized关键字相同的功能,而且更为灵活,在极端的情况下性能会更好一些。一起来看一下吧
private final ReentrantLock asd = new ReentrantLock();
private int a;
public void run() {
int begin = 10000;
while (begin > 0) {
try {
asd.lock();
a ++;
} finally {
asd.unlock();
}
begin --;
}
}
}
当线程执行到try块之后,首先通过asd.lock()获得锁,获得锁之后再执行a++,最后在finally语句块中通过asd的unlock方法释放锁。
ThreadLocal
我们需要在同一个线程中共享一个变量,一个最直接的办法就是创建一个共享的散列表,用线程对象作为键,需要线程中共享的变量作为值保存起来,每次使用散列表.get(Thread.currentThread())的方式获取。ThreadLocal用来解决多线程程序的并发问题。
public class ThreadTask {
ThreadLocal<Integer> a=new ThreadLocal<Integer>() {
protected Integer initialValue() {
return 10;
}
};
public int get() {
return a.get();
}
public void set() {
a.set(a.get()+1);
}
}
原子操作类
原子操作类相当于泛化的volatile变量,能够支持原子读取-修改-写操作,原子操作类在Java.util.concurrent.atomic包下,可以分为
原子更新基本类型
原子更新数组类型
原子更新引用
原子更新属性
使用原子的方式更新基本类型,Atomic包提供了以下3个类。
AtomicBoolean:原子更新布尔类型。
AtomicInteger:原子更新整型。
AtomicLong:原子更新Long类型。
以上3个类提供的方法几乎一模一样,以AtomicInteger为例常用方法如下:
int addAndGet(int delta): 以原子方式将输入的数值与实例中的值(AtomicInteger里的value)相加,并返回结果。
boolean compareAndSet(int expect,int update):如果输入的数值等于预期值,则以原子方式将该值设置为输入的值。
生产者-消费者模式
一块缓冲区作为仓库,生产者可以将产品放入仓库,消费者则可以从仓库中取走产品。
生产者仅仅在仓储未满时候生产,仓满则停止生产。
消费者仅仅在仓储有产品时候才能消费,仓空则等待。
当消费者发现仓储没产品可消费时候会通知生产者生产。
生产者在生产出可消费产品时候,应该通知等待的消费者去消费。
package com.threadTask;
public class Add{
class Product{
String name;
float price;
boolean isTrue=false;//是否开始生产
}
class Sale extends Thread{
private Product p=null;
public Sale(Product p){
this.p=p;
}
public void run() {
int i=0;
while(true){
synchronized (p) {
if(p.isTrue==false){
if(i%2==0){
p.name="糖";
p.price=4;
System.out.println("生产者生产");
}else{
p.name="饮料";
p.price=2.5f;
System.out.println("生产者生产了");
}
p.isTrue=true;
i++;
}else{
}
}
}
}
}
class Custom extends Thread{
private Product p=null;
public Custom(Product p){
this.p=p;
}
public void run() {
while(true){
synchronized (p) {
if(p.isTrue){
System.out.println("消费者生产了:"+p.name);
p.isTrue=false;
}else{
p.notify(); //消费暂停,开始生产
}
}
}
}
}
public class Producer_Custom {
public void main(String[] args) {
Product p=new Product();
Sale sale=new Sale(p);
sale.start();
Custom custom=new Custom(p);
custom.start();
}
}
}
资历尚浅,还请包涵。