线程同步组件

控制并发访问资源

     semaphore是一个计数器,保护访问一个或多个共享资源。当一个线程要访问一个共享资源时,首先需要获取semaphore,如果semaphore内部计数器大于0,semaphore的计数器减一,并且允许访问共享资源。计数器大于0,意味着存在free资源可以被使用。否则,如果semaphore的计数器为0,semaphore将线程置入sleep状态,直到计数器大于0。semaphore的计数器为0,意味着所有的共享资源被其他线程使用。当线程完成了共享资源,必须释放semaphore,其他线程可以访问共享线程。
Semaphore semaphore = new Semaphore(1);
public void printJob (Object document){
   try {
      semaphore.acquire();
      long duration=(long)(Math.random()*10);
      System.out.printf("%s: PrintQueue: Printing a Job during %d 
seconds\n",Thread.currentThread().getName(),duration);
      Thread.sleep(duration);   
      } catch (InterruptedException e) {
      e.printStackTrace();
    } finally {
      semaphore.release();      
    }
}
semaphore.acquire()//阻塞其他线程,直到semaphore被释放,在阻塞期间线程可以被中断,抛出InterruptedException异常
semaphore.acquireUninterruptibly()//此版本忽略中断,不抛出异常
tryAcquire()//如果没有获得,返回false,且不会被阻塞

控制并发访问多个资源

private boolean freePrinters[] = new boolean[3];
Lock lockPrinters = new ReentrantLock();
Semaphore semaphore = new Semaphore(3);  
public void printJob (Object document){
	try {
      semaphore.acquire();//允许同时三个线程进入访问打印机
      int assignedPrinter=getPrinter();//获取打印机
      long duration=(long)(Math.random()*10);
      System.out.printf("%s: PrintQueue: Printing a Job in Printer 
          %d during %d seconds\n",Thread.currentThread().getName(),\
          assignedPrinter,duration);
      TimeUnit.SECONDS.sleep(duration);
      freePrinters[assignedPrinter]=true;
    } catch (InterruptedException e) {
      e.printStackTrace();
    } finally {
      semaphore.release();      
    }
}

private int getPrinter() {
  try {
      lockPrinters.lock();//
      for (int i=0; i<freePrinters.length; i++) {
      if (freePrinters[i]){
        ret=i;
        freePrinters[i]=false;
        break;
      }
    }catch (Exception e) {
      e.printStackTrace();
    } finally {
      lockPrinters.unlock();
    }
    return ret;
}

等待多个并发事件

    Java提供了允许一个或多个线程等待直到一组操作完成: CountDownLatch,它用一个整数来初始化,即等待操作数目,当一个线程等待这些操作完成时,使用await()方法,此方法将线程置入sleep状态直到操作完成。当一个操作完成时调用countDown()。
CountDownLatch controller = new CountDownLatch(number);

controller.countDown();//操作线程调用
try {
      controller.await();//等待线程
      System.out.printf("VideoConference: All the participants 
have come\n");
      System.out.printf("VideoConference: Let's start...\n");
} catch (InterruptedException e) {
      e.printStackTrace();
}
    当创建CountDownLatch对象,使用构造器参数来初始化内部计数器,每一次线程调用countDown()方法,CountDownLatch对象的内部计数器自减1,当内部计数器为0时,CountDownLatch对象唤醒在await()方法中等待的线程。一旦计数器为0,所有调用await()方法立即返回,所有countDown()调用都不会生效。 CountDownLatch机制用多个任务来同步一个或多个线程。如果需要重新同步,需要创建新的CountDownLatch对象。

并发任务之间交换数据

    Java提供了在两并行线程之间交换数据的同步组件。Exchanger类允许定义两线程之间的同步点,当两个线程到达这个点时,他们交换数据结构,第一个线程的数据结构流向第二个线程,而第二个线程的数据流向第一个线程。
public class ThreadLocalTest {    
    public static void main(String[] args) {  
        Exchanger<List<Integer>> exchanger = new Exchanger<>();  
        new Consumer(exchanger).start();  
        new Producer(exchanger).start();  
    }    
}  
  
class Producer extends Thread {  
    List<Integer> list = new ArrayList<>();  
    Exchanger<List<Integer>> exchanger = null;  
    public Producer(Exchanger<List<Integer>> exchanger) {  
        super();  
        this.exchanger = exchanger;  
    }  
    @Override  
    public void run() {  
        Random rand = new Random();  
        for(int i=0; i<10; i++) {  
            list.clear();  
            list.add(rand.nextInt(10000));  
            list.add(rand.nextInt(10000));  
            list.add(rand.nextInt(10000));  
            list.add(rand.nextInt(10000));  
            list.add(rand.nextInt(10000));  
            try {  
                list = exchanger.exchange(list);  
            } catch (InterruptedException e) {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
            }  
        }  
    }  
}    
class Consumer extends Thread {  
    List<Integer> list = new ArrayList<>();  
    Exchanger<List<Integer>> exchanger = null;  
    public Consumer(Exchanger<List<Integer>> exchanger) {  
        super();  
        this.exchanger = exchanger;  
    }  
    @Override  
    public void run() {  
        for(int i=0; i<10; i++) {  
            try {  
                list = exchanger.exchange(list);  
            } catch (InterruptedException e) {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
            }  
            System.out.print(list.get(0)+", ");  
            System.out.print(list.get(1)+", ");  
            System.out.print(list.get(2)+", ");  
            System.out.print(list.get(3)+", ");  
            System.out.println(list.get(4)+", ");  
        }  
    }  
}  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值