Java基础学习之JDK5.0中的并发

@[TOC]Java基础学习之JDK5.0中的并发

Java基础学习之JDK5.0中的并发

向大家分享一下个人对JDK5并发知识的学习。

(1)、所在的包

Java.util.concurrent

(2)、对比1.4和5.0的线程

5.01.4
ExecutorService取代Thread
Callable & Future取代Runnable
Lock取代Synchronized
SignalAll取代notifyAll()
await()取代wait()

(3)、 三个新加的多线程包

Java 5.0里新加入了三个多线程包:`

java.util.concurrent, 
java.util.concurrent.atomic,
java.util.concurrent.locks. 
java.util.concurrent包含了常用的多线程工具,是新的多线程工具的主体。 
java.util.concurrent.atomic包含了不用加锁情况下就能改变值的原子变量,比如说AtomicInteger提供了addAndGet()方法。Add和Get是两个不同的操作,为了保证别的线程不干扰,以往的做法是先锁定共享的变量,然后在锁定的范围内进行两步操作。但用AtomicInteger.addAndGet()就不用担心锁定的事了,其内部实现保证了这两步操作是在原子量级发生的,不会被别的线程干扰。
java.util.concurrent.locks包包含锁定的工具。

(4)、 Callable 和 Future接口

Executor接口替代了Thread类,他可以创建定量的和动态以及周期性的线程池。
ExecutorService接口,线程池,用来存放线程来节省创建和销毁资源的消耗。
Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其它线程执行的任务。CallableRunnable有几点不同:

  1. Callable规定的方法是call(),而Runnable规定的方法是run().
  2. Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。
  3. call()方法可抛出异常,而run()方法是不能抛出异常的。

Future对象可以获得线程运行的返回值
运行Callable任务可拿到一个Future对象,通过Future对象可了解任务执行情况,可取消任务的执行,还可获取任务执行的结果。
以下是Callable的一个例子:

    public class DoCallStuff implements Callable{ // *1
            private int aInt;
            public DoCallStuff(int aInt) {
                    this.aInt = aInt;
            }
            public String call() throws Exception { //*2
                    boolean resultOk = false;
                    if(aInt == 0){
                            resultOk = true;
                    }  else if(aInt == 1){
                            while(true){ //infinite loop
                                    System.out.println("looping....");
                                    Thread.sleep(3000);
                            }
                    } else {
                            throw new Exception("Callable terminated with Exception!"); //*3
                    }
                    if(resultOk){
                            return "Task done.";
                    } else {
                            return "Task failed";
                    }
            }
    }
*1: 名为DoCallStuff类实现了Callable,String将是call方法的返回值类型。例子中用了String,但可以是任何Java类。
*2: call方法的返回值类型为String,这是和类的定义相对应的。并且可以抛出异常。
*3: call方法可以抛出异常,如加重的斜体字所示。

以下是调用DoCallStuff的主程序。

import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    public class Executor {
            public static void main(String[] args){
                    //*1
                    DoCallStuff call1 = new DoCallStuff(0);
                    DoCallStuff call2 = new DoCallStuff(1);
                    DoCallStuff call3 = new DoCallStuff(2);
                    //*2
                    ExecutorService es = Executors.newFixedThreadPool(3);
                    //*3
                    Future future1 = es.submit(call1);
                    Future future2 = es.submit(call2);
                    Future future3 = es.submit(call3);
                    try {
                            //*4
                            System.out.println(future1.get());
                             //*5
                            Thread.sleep(3000);
                            System.out.println("Thread 2 terminated? :" + future2.cancel(true));
                            //*6
                            System.out.println(future3.get());
                    } catch (ExecutionException ex) {
                            ex.printStackTrace();
                    } catch (InterruptedException ex) {
                            ex.printStackTrace();
                    }
            }
    }
*1: 定义了几个任务
*2: 初始了任务执行工具。任务的执行框架将会在后面解释。
*3: 执行任务,任务启动时返回了一个Future对象,如果想得到任务执行的结果或者是异常可对这个Future对象进行操作。Future所含的值必须跟Callable所含的值对映,比如说例子中Future对印Callable
*4: 任务1正常执行完毕,future1.get()会返回线程的值
*5: 任务2在进行一个死循环,调用future2.cancel(true)来中止此线程。传入的参数标明是否可打断线程,true表明可以打断。
*6: 任务3抛出异常,调用future3.get()时会引起异常的抛出。

运行Executor会有以下运行结果:

looping....
    Task done. //*1
    looping....
    looping....//*2
    looping....
    looping....
    looping....
    looping....
    Thread 2 terminated? :true //*3
    //*4
    java.util.concurrent.ExecutionException: java.lang.Exception: Callable terminated with Exception!
            at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:205)
            at java.util.concurrent.FutureTask.get(FutureTask.java:80)
            at concurrent.Executor.main(Executor.java:43)
            …….
*1: 任务1正常结束
*2: 任务2是个死循环,这是它的打印结果
*3: 指示任务2被取消
*4: 在执行future3.get()时得到任务3抛出的异常

(5)、 Lock接口

实现类ReentrantLock
我们可以用lock对象,来对临界资源加锁,只有获得lock对象才能访问临界资源,如果没有获得lock对象,就会进入lock对象的锁池。
trylock()方法会返回布尔值,这个方法是用来判断这个锁对象是不是已经被线程获取,如果返回值为true,则会直接获得这个锁对象,如果返回false,线程不会阻塞还会继续运行。

    Lock lock=new ReentrantLock();
    publci void test(){
       try{
      lock.lock();//加锁
      .....//需要加锁的临界资源。
      }finally{
        lock.unlock();//解锁。
      }
    }

(6)、 ReadWriteLock读写锁接口

ReentrantReadWriteLockReadWriteLock的实现类。
readLock()分配读锁,读锁可以分配多个线程,但是在分配读锁后所有读锁释放前,写锁时不能分配的。
Lock writeLock() 写锁只能分配给一个线程,在分配写锁后写锁是放前,读锁不能被分配。

(7)、 Condition接口和实现类

await()替代了wait()方法。
notify()notifyAll() 在JDK5.0中已经用signal()signalAll()方法替换掉了,在JDK5.0中,可以使用多个等待队来存放等待的线程,并对线程进行分类。

(8)、 Queue接口(Collection的子接口,对列接口)

LinkedList也实现了这个在JDK5.0中的新接口Queue,并且这个类自动的实现了生产者和消费者的同步。

(8)、 JDK5.0的高级同步

Semaphore类(信号量)也就是可以向线程分配许可证,指定许可证数量可以实现多线程的同步。
Semaphore s=new Semaphore(4);//可以分配4个许可证,许可证都被分配出去时,得不到许可证的线程就会阻塞。
acquire()方法,获得许可证。release() 方法,释放一个许可证,也有相应的方法指定释放和获得许可证的数量的方法。
CountDownLatch类:
CountDownLatch中有个计数器,访问这个类的对象就会从计数器中减一,countDown()方法会将原有的设置的计数器值减一,当countdown计数器为零时会使放所有await()的线程。
CyclicBarrier
CyclicBarrierCountDownLatch比较相似
CyclicBarrier在构造时给出线程数,只有等待的线程数到了构造方法中指定的数量,当最后一个线程等待后,所有的线程都会被释放,这个类是一个多线程汇合的工具。Exchanger类,用exchange()方法可以使两个线程间相互交换对象,在两线程的同步点,等待第二个线程。在同步点时,交换对象,并同时被释放。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值