Concurrent - Semaphore - Semaphore(int permits)

原创转载请注明出处:http://agilestyle.iteye.com/blog/2342878

 

Semaphore所提供的功能完全是synchronized关键字的升级版,但它提供的功能更加的强大和方便,主要的作用是控制线程并发的数量

Semaphore(int permits)


 

设置permits为1

Service.java

package org.fool.java.concurrent.semaphore;

import java.util.concurrent.Semaphore;

public class Service {
    private Semaphore semaphore = new Semaphore(1);

    public void testMethod() {
        try {
            semaphore.acquire();

            System.out.println(Thread.currentThread().getName() + " begin timer=" + System.currentTimeMillis());

            Thread.sleep(5000);

            System.out.println(Thread.currentThread().getName() + " end timer=" + System.currentTimeMillis());

            semaphore.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Note:

permits代表同一时间内,最多允许多少个线程同时执行acquire()和release()之间的代码。

本例设置为1,所以最多只有1个线程同时执行acquire()和release()之间的代码。

ThreadA.java

package org.fool.java.concurrent.semaphore;

public class ThreadA implements Runnable {
    private Service service;

    public ThreadA(Service service) {
        this.service = service;
    }

    @Override
    public void run() {
        service.testMethod();
    }
}

ThreadB.java

package org.fool.java.concurrent.semaphore;

public class ThreadB implements Runnable {
    private Service service;

    public ThreadB(Service service) {
        this.service = service;
    }

    @Override
    public void run() {
        service.testMethod();
    }
}

ThreadC.java

package org.fool.java.concurrent.semaphore;

public class ThreadC implements Runnable {
    private Service service;

    public ThreadC(Service service) {
        this.service = service;
    }

    @Override
    public void run() {
        service.testMethod();
    }
}

SemaphoreTest.java

package org.fool.java.concurrent.semaphore;

public class SemaphoreTest {
    public static void main(String[] args) {
        Service service = new Service();

        Thread a = new Thread(new ThreadA(service));
        Thread b = new Thread(new ThreadA(service));
        Thread c = new Thread(new ThreadA(service));

        a.setName("A");
        b.setName("B");
        c.setName("C");

        a.start();
        b.start();
        c.start();
    }
}

Run


Note:

private Semaphore semaphore = new Semaphore(1);

由于定义了最多1个线程执行acquire()和release()之间的代码,所以打印的结果就是3个线程是同步的,线程A执行结束的时间和线程B执行开始的时间相同,线程B执行结束的时间和线程C还行开始的时间相同。

 

修改Service.java,设置permits为2

private Semaphore semaphore = new Semaphore(2);

再次Run SemaphoreTest


Note:

由于定义了最多2个线程执行acquire()和release()之间的代码,所以线程A和线程B执行开始的时间是相同的,需要注意的是,对Semaphore的构造方法传递的参数permits值如果大于1时,该类并不能保证线程的安全性,因为还是有可能会出现多个线程共同访问实例变量,导致出现脏读。

 

Semaphore(int permits, boolean fair)

有些时候,获得permits的顺序与线程启动的顺序有关,这时信号量就要分为公平和非公平的。

公平信号量是获得锁的顺序与线程启动的顺序有关,但不代表100%地获得信号量,仅仅是在概率上能得到保证。

非公平信号量即获得锁的顺序与线程启动的顺序无关。

Service.java

package org.fool.java.concurrent.semaphore.fair;

import java.util.concurrent.Semaphore;

public class Service {
    private boolean isFair = false;
    private Semaphore semaphore = new Semaphore(1, isFair);

    public void testMethod() {
        try {
            semaphore.acquire();
            System.out.println(Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            semaphore.release();
        }
    }
}

Note:

设置了非公平信号量

private boolean isFair = false;

 

ThreadA.java

package org.fool.java.concurrent.semaphore.fair;

public class ThreadA implements Runnable {
    private Service service;

    public ThreadA(Service service) {
        this.service = service;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " invoked...");
        service.testMethod();
    }
}

FairTest.java

package org.fool.java.concurrent.semaphore.fair;

public class FairTest {
    public static void main(String[] args) {
        Service service = new Service();

        Thread a = new Thread(new ThreadA(service));
        a.start();

        for(int i = 0; i < 4; i++) {
            new Thread(new ThreadA(service)).start();
        }
    }
}

 

Run

非公平信号量运行的效果是线程启动的顺序与调用semaphore.acquire()的顺序无关,也就是线程先启动了并不代表获得permits


 

修改Service.java,设置公平信号量

private boolean isFair = true;

 

再Run

公平信号量运行的效果是线程启动的顺序与调用semaphore.acquire()的顺序有关,也就是先启动的线程优先获得permits

 

 

 

 

 

 

 

猜你喜欢

转载自agilestyle.iteye.com/blog/2342878