黑马程序员_java多线程与并发库高级应用

------- android培训java培训、期待与您交流! ---------- 

 

一、传统线程技术

传统是相对于JDK1.5而言的

传统线程技术与JDK1.5的线程并发库

线程就是程序的一条执行线索/线路。

创建线程的两种传统方式

1创建Thread的子类,覆盖其中的run方法,运行这个子类的start方法即可开启线程

2创建Thread时传递一个实现Runnable接口的对象实例

总结:查看Thread类的run()方法的源代码,可以看到其实这两种方式都是在调用Thread对象的run方法,如果Thread类的run方法没有被覆盖,并且为该Thread对象设置了一个Runnable对象,该run方法会调用Runnable对象的run方法。

多线程并不一定会提高程序的运行效率。

多线程下载:并不是自己电脑快了,而是抢到更多服务器资源。

3)当在Thread子类中覆盖了run方法并编写了运行代码,也为Thread子类对象传递了一个Runnable对象,那么线程在运行时执行的是子类所覆盖的run方法。

1).public staticvoid main(String[] args) {

      

             Threadthread = new Thread(){

                    @Override

                    public void run() {

                           while(true){

                                  try {

                                         Thread.sleep(500);

                                  } catch (InterruptedException e) {

                                         e.printStackTrace();

                                  }

                                  System.out.println("1:" +Thread.currentThread().getName());

                                  System.out.println("2:" +this.getName());

                           }

                    }

             };

             thread.start();

2).Threadthread2 = new Thread(new Runnable(){

                    @Override

                    public void run() {

                           while(true){

                                  try {

                                         Thread.sleep(500);

                                  } catch (InterruptedException e) {

                                         e.printStackTrace();

                                  }

                                  System.out.println("1:" +Thread.currentThread().getName());

                           }                         

                          

                    }

             });

             thread2.start();

3).new Thread(

                           newRunnable(){

                                  public void run() {

                                         while(true){

                                                try {

                                                       Thread.sleep(500);

                                                } catch (InterruptedException e) {

                                                       e.printStackTrace();

                                                }

                                                System.out.println("runnable :"+ Thread.currentThread().getName());

                                         }                                              

                                  }

                           }

             ){

                    public void run() {

                           while(true){

                                  try {

                                         Thread.sleep(500);

                                  } catch (InterruptedException e) {

                                         e.printStackTrace();

                                  }

                                  System.out.println("thread :" +Thread.currentThread().getName());

                           }    

                    }

             }.start();

      }

 

二、传统定时器

传统定时器的创建:直接使用定时器类Timer

a、过多长时间后炸

newTimer().schedule(TimerTask定时任务, Date time定的时间);

b、过多长时间后炸,以后每隔多少时间再炸

newTimer().schedule(TimerTask定时任务, Long延迟(第一次执行)时间, Long间隔时间);

TimerTaskRunnable类似,有一个run方法

Timer是定时器对象,到时间后会触发炸弹(TimerTask)对象

注意:内部类中不能声明静态变量

       定义一个静态变量private static count = 0;

       run方法内部:count=count+1%2

       将定时器的时间设置为:2000+2000*count

示例:

private static int count = 0;

       public static voidmain(String[] args) {

              class MyTimerTask extends TimerTask{

                    

                     @Override

                     public void run(){

                            count = (count+1)%2;

                            System.out.println("bombing!");

                            new Timer().schedule(newMyTimerTask(),2000+2000*count);

                     }

              }

              new Timer().schedule(new MyTimerTask(), 2000);

             

              while(true){

                     System.out.println(newDate().getSeconds());

                     try {

                            Thread.sleep(1000);

                     } catch(InterruptedException e) {

                            // TODO Auto-generated catch block

                            e.printStackTrace();

                     }

              }

       }

定时器还可以设置具体时间。

 

三、传统线程互斥技术

需要注意的地方:

内部类不能访问局部变量,要访问需加final

静态方法中不能创建内部类的实例对象。

互斥方法:

             同步代码块:synchronized (lock){}

             同步方法:方法返回值前加synchronized同步方法上边用的锁就是this对象,静        态同步方法使用的锁是该方法所在的class文件对象

使用synchronized关键字实现互斥,要保证同步的地方使用的是同一个锁对象。

      

四、传统线程同步通信技术

小总结:要用到共同数据(包括同步锁)或相同算法的多个方法要封装在一个类中,锁是上在代表要操作的资源类的内部方法中的,而不是上在线程代码中的。这样写出来的类就是天然同步的,只要使用的是同一个new出来的对象,那么这个对象就具有同步互斥特性。

判断唤醒等待标记时使用while增加程序健壮性,防止伪唤醒。

 

五、ThreadLocal实现线程范围的共享变量

JDK1.5提供了ThreadLocal类来方便实现线程范围内的数据共享,它的作用就相当于上一节中的Map

 

importjava.util.Map;

importjava.util.Random;

 

public classThreadLocalTest {

 

      private static ThreadLocal<Integer>x = new ThreadLocal<Integer>();

      private staticThreadLocal<MyThreadScopeData> myThreadScopeData =     

     new ThreadLocal<MyThreadScopeData>();

      public static void main(String[] args) {

             for(inti=0;i<2;i++){

                    new Thread(new Runnable(){

                           @Override

                           publicvoid run() {

                           intdata = new Random().nextInt();

     System.out.println(Thread.currentThread().getName() + " has put data :" + data);

                                  x.set(data);                             

      MyThreadScopeData.getThreadInstance().setName("name"+ data);

            MyThreadScopeData.getThreadInstance().setAge(data);

                                  new A().get();

                                  new B().get();

                           }

                    }).start();

             }

      }

      static class A{

             publicvoid get(){

                    int data = x.get();

System.out.println("Afrom " + Thread.currentThread().getName()+ " get data :" + data);

      MyThreadScopeData myData =MyThreadScopeData.getThreadInstance();

      System.out.println("A from " +Thread.currentThread().getName()

                                  + " getMyData: " +myData.getName() + "," +

                                  myData.getAge());

             }

      }

 

六、java原子性操作类的应用

Java5的线程并发库

       java.util.concurrent在并发编程中很常用的实用工具类。

                     |----locks为锁和等待条件提供一个框架的接口和类,

它不同于内置同步和监视器

                     |----atomic类的小工具包,支持在单个变量上解除锁的线程安全编程。

                           可以对基本类型、数组中的基本类型、类中的基本类型等进行操作

                            |----AtomicInteger

 

七、java线程并发库的应用

1.线程池:先创建多个线程放在线程池中,当有任务需要执行时,从线程池中找一个空闲线程执行任务,任务完成后,并不销毁线程,而是返回线程池,等待新的任务安排。

2.线程池编程中,任务是提交给整个线程池的,并不是提交给某个具体的线程,而是由线程池从中挑选一个空闲线程来运行任务。一个线程同时只能执行一个任务,可以同时向一个线程池提交多个任务。

3.线程池创建方法:

1)创建一个拥有固定线程数的线程池。

              ExecutorService threadPool =Executors.newFixedThreadPool(3);   

2)创建一个缓存线程池。

              ExecutorService threadPool =Executors.newCacheThreadPool();

3)创建一个只有一个线程的线程池。

              ExecutorService threadPool =Executors.newSingleThreadExector();

4)往线程池中添加任务。

              threadPool.executor(Runnable)

5)关闭线程池。

              threadPool.shutdown()  线程全部空闲,没有任务就关闭线程池

              threadPool.shutdownNow() 不管任务有没有做完,都关掉

 

八、 Callable与Future的应用:

1)Future取得的结果类型和Callable返回的结果类型必须一致,这是通过泛型来实现的。

2)Callable要采用ExecutorService的submit方法提交,返回的future对象可以取消任务。

3)CompletionService用于提交一组的Callable任务,其take方法返回已完成的一个Callable任务对应的Future对象。

示例如下:

 

publicclass CallableAndFuture {

       public static void main(String[] args) {

         ExecutorServicethreadPool = Executors.newSingleThreadExecutor();

         Future<String>future =

                threadPool.submit(

                       newCallable<String>() {

                              public String call() throws Exception {

                                     Thread.sleep(2000);

                                     return"hello";

                              };

                       }

         );

         System.out.println("等待结果");

         try{

                System.out.println("拿到结果:" + future.get());

         }catch (InterruptedException e) {

                e.printStackTrace();

         }catch (Exception e) {

                e.printStackTrace();

         }

 

九、java5的线程锁技术

总结:1.Lock比传统线程模型中的synchronized更加面向对象,锁本身也是一个对象,两个线程执行的代码要实现同步互斥效果,就要使用同一个锁对象。锁要上在要操作的资源类的内部方法中,而不是线程代码中。

2.锁定和取消锁定出现在不同作用范围中时,必须谨慎地确保保持锁定时所执行的所有代码用 try-finally try-catch 加以保护,以确保在必要时释放锁。

 

十、Condition的应用

1.Condition的功能类似在传统线程技术中的Object.wait()Object.natify()的功能,传统线程技术实现的互斥只能一个线程单独干,不能说这个线程干完了通知另一个线程来干,Condition就是解决这个问题的,实现线程间的通信。

2.Condition实例实质上被绑定到一个锁上。要为特定 Lock 实例获得 Condition实例,请使用其 newCondition()方法。

 

十一、Lock和Condition的应用

static class Business {

                    Locklock = new ReentrantLock();

                    Conditioncondition1 = lock.newCondition();

                    Conditioncondition2 = lock.newCondition();

                    Conditioncondition3 = lock.newCondition();

                    private int shouldSub = 1;

                   public  void sub2(int i){

                      lock.lock();

                      try{

                            while(shouldSub != 2){

                                    try {

                                         condition2.await();

                                  }catch (Exception e) {

                                         // TODO Auto-generated catch block

                                         e.printStackTrace();

                                  }

                             }

                                  for(intj=1;j<=10;j++){

                           System.out.println("sub2 threadsequence of " + j + ",loop of " + i);

                                  }

                            shouldSub = 3;

                            condition3.signal();

                      }finally{

                            lock.unlock();

                      }

               }

 

 public  void sub3(int i){

                      lock.lock();

                      try{

                            while(shouldSub != 3){

                                    try {

                                         condition3.await();

                                  }catch (Exception e) {

                                         // TODO Auto-generated catch block

                                         e.printStackTrace();

                                  }

                             }

                                  for(intj=1;j<=20;j++){

                           System.out.println("sub3 threadsequence of " + j + ",loop of " + i);

                                  }

                            shouldSub = 1;

                            condition1.signal();

                      }finally{

                            lock.unlock();

                      }

               }         

              

              public  void main(int i){

                      lock.lock();

                      try{

                            while(shouldSub != 1){

                                       try{

                                                condition1.await();

                                         } catch (Exception e) {

                                                e.printStackTrace();

                                         }

                                }

                                  for(intj=1;j<=100;j++){

                           System.out.println("main threadsequence of " + j + ",loop of " + i);

                                  }

                                  shouldSub= 2;

                                  condition2.signal();

              }finally{

                      lock.unlock();

               }

        }

 

十二、Semphore:实现信号灯,通常用于限制可以访问的某些资源的线程数目

Semaphore可以维护当前访问自身的线程个数,并且提供了同步机制。

Semaphore通常用于限制可以访问某些资源(物理或逻辑的)的线程数目。

Semaphore只对可用许可的号码进行计数,并采取相应的行动。

Semphoresp = new Semphore(6);

sp.availablePermits();

sp.acquire();//请求

 sp.release();//释放,添加一个许可,从而可能释放一个正在阻塞的获取者

 

总结:传统互斥只能内部释放锁this.unlock(),进去this.lock()晕倒了别人就没法进去了;用信号灯可以外部释放,其他线程可以释放再获取sp.release()   sp.acquire()。

 

十三、CyclicBarrier

集合等待,他允许一组线程互相等待,直到到达某个公共屏障点。

CyclicBarrier cb = newCyclicBarrier(3);

cb.await();//到了其他人没来就等

cb.getNumberWaiting();//当前等待数量

总结:CyclicBarrier支持一个可选的 Runnable 命令,在一组线程中的最后一个线程到达之后(但在释放所有线程之前),该命令只在每个屏障点运行一次。

 

十四、CountDownLatch同步工具

倒计时计数器,调用CountDownLatch对象的countDown方法,一个同步辅助类,在完成一组正在其他线程中执行的操作之前,他允许一个或多个线程等待。

 

十五、Exchanger:数据交换

用于实现两个数据之间的交换。

exchanger.eachange(data)//将自己的数据交换出去

exchange():等待另一个线程到达此交换点,然后将给定的线程传送给该线程,并接受该线程的对象。

 

十六、ArrayBlockingQueue:可阻塞的队列

BlockingQueue queue = newArrayBlockingQueue(3);

queue.put(1);//如果放满就会堵塞

queue.take();//移除元素

BlockingQueue方法以四种形式出现,对于不能立即满足但可能在将来某一时刻可以满足的操作,这四种形式的处理方式不同:第一种是抛出一个异常,第二种是返回一个特殊值(null false,具体取决于操作),第三种是在操作可以成功前,无限期地阻塞当前线程,第四种是在放弃前只在给定的最大时间限制内阻塞。下表中总结了这些方法:

 

抛出异常

特殊值

阻塞

超时

插入

add(e)

offer(e)

put(e)

offer(e,  time, unit)

移除

remove()

poll()

take()

poll(time,  unit)

检查

element()

peek()

不可用

不可用

 

总结:

BlockingQueue不接受 null元素。

BlockingQueue实现主要用于生产者-使用者队列,但它另外还支持Collection接口。

BlockingQueue实现是线程安全的。

 

------- android培训java培训、期待与您交流! ---------- 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值