黑马程序员_基础加强三

时间:2021-12-02 00:42:18

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

 

传统线程技术回顾

1.线程就是程序的一条执行的线路。多线程并不一定会提高程序的运行效率。

2.创建线程的两种传统方式

(1)创建Thread的子类,覆盖其中的run方法。

Thread thread1 =new Thread(){

public void run()

try{

Thread.seelp(20) ;让线程暂停

}catch(InterruptedException e){

e.printStackTrace();

}

System.out.println(Thread. currentThread().getName());//获取当前线程对象名字

}

} .start();

(2)在传递给Thread对象的Runnable对象的run方法中编写代码。

Thread thread2 =new Thread(new Runnable(){

       public void run() {

              while(true){

                            try {

                                   Thread.sleep(500);

                            } catch(InterruptedException e) {

                                   e.printStackTrace();

                            }

                            System.out.println(Thread.currentThread().getName());

                     }

              }

       }).start();

总结:

Thread类中的run方法源代码中看出,两种传统创建线程的方式都是在调用Thread对象的run方法,如果Thread对象的run方法没有被覆盖,并且像上边的问题那样为Thread对象传递了一个Runnable对象,就会调用Runnable对象的run方法。

 

传统定时器技术回顾

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

示例

import java.util.Date;

import java.util.Timer;

import java.util.TimerTask;

public class TraditionalTimerTest {

       privatestatic int count = 0;

public staticvoid main(String[] args) {

              classMyTimerTask extends TimerTask{

              @Override

              public void run() {

                     count= (count+1)%2;

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

                     newTimer().schedule(new MyTimerTask(),2000+2000*count);

              }

       }

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

      

       while(true){

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

              try {

                     Thread.sleep(1000);

              } catch (InterruptedException e) {

                     e.printStackTrace();

              }

              }

       }

}

 

传统线程互斥技术

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

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

3.互斥方法:

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

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

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

 

传统线程同步通信技术

1.锁是上在代表要操作的资源类的内部方法中的,而不是上在线程代码中的。这样写出来的类就是天然同步的,只要使用的是同一个new出来的对象,那么这个对象就具有同步互斥特性。

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

 

ThreadLocal类及应用技巧

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

2.每个线程调用全局ThreadLocal对象的set方法,就相当于往其内部的map集合中增加一条记录,key就是各自的线程,value就是各自的set方法传进去的值。

3.在线程结束时可以调用ThreadLocal.clear()方法用来更快释放内存,也可以不调用,因为线程结束后也可以自动释放相关的ThreadLocal变量。

4.一个ThreadLocal对象只能记录一个线程内部的一个共享变量,需要记录多个共享数据,可以创建多个ThreadLocal对象,或者将这些数据进行封装,将封装后的数据对象存入ThreadLocal对象中。

示例

import java.util.HashMap;

import java.util.Map;

import java.util.Random;

 

public class ThreadLocalTest {

 

       privatestatic ThreadLocal<Integer> x = new ThreadLocal<Integer>();

       privatestatic ThreadLocal<MyThreadScopeData> myThreadScopeData =

 newThreadLocal<MyThreadScopeData>();

       publicstatic void main(String[] args) {

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

                     newThread(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);

                                   newA().get();

                                   newB().get();

                            }

                     }).start();

              }

       }

      

static class A{

       publicvoid get(){

              intdata = x.get();

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

              MyThreadScopeDatamyData = MyThreadScopeData.getThreadInstance();

System.out.println("A from " +Thread.currentThread().getName() + " getMyData: " + myData.getName()+ "," +myData.getAge());

       }

}

 

线程并发库的应用

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

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

3.线程池创建方法:

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

              ExecutorService threadPool =Executors.newFixedThreadPool(2);   

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

ExecutorService threadPool = Executors.newCacheThreadPool();

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

              ExecutorService threadPool =Executors.newSingleThreadExector();

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

              threadPool.executor(Runnable)

(5)关闭线程池

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

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

 

CallableFuture的应用

1.获取一个线程的运行结果。

2.public interface Callable<V>

       Future取得的结果类型和Callable返回的结果类型必须一致,通过泛型实现。Callable要通过ExecutorServicesubmit方法提交,返回的Future对象可以取消任务。

3.public interface Future<V>

Future 表示异步计算的结果。

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

示例

import java.util.Random;

import java.util.concurrent.Callable;

importjava.util.concurrent.CompletionService;

importjava.util.concurrent.ExecutionException;

importjava.util.concurrent.ExecutorCompletionService;

importjava.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.Future;

import java.util.concurrent.TimeUnit;

public class CallableAndFuture {

       publicstatic void main(String[] args) {

              ExecutorServicethreadPool = Executors.newSingleThreadExecutor();

              Future<String>future =

                     threadPool.submit(

                            newCallable<String>() {

                                   publicString 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();

              }

ExecutorService threadPool2 =

 Executors.newFixedThreadPool(10);CompletionService<Integer>

completionService = newExecutorCompletionService<Integer>(threadPool2);

              for(inti=1;i<=10;i++){

                     finalint seq = i;

                     completionService.submit(newCallable<Integer>() {

                            @Override

                            publicInteger call() throws Exception {

                                   Thread.sleep(newRandom().nextInt(5000));

                                   returnseq;

                            }

                     });

              }

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

                     try{

                            System.out.println(

                                          completionService.take().get());

                     }catch (InterruptedException e) {

                            e.printStackTrace();

                     }catch (ExecutionException e) {

                            e.printStackTrace();

                     }

              }

       }

}

 

线程锁技术

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

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

 

条件阻塞Condition的应用

1.Condition Object 监视器方法(waitnotifynotifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。

示例

importjava.util.concurrent.atomic.AtomicInteger;

import java.util.concurrent.locks.Condition;

import java.util.concurrent.locks.Lock;

importjava.util.concurrent.locks.ReentrantLock;

public class ThreeConditionCommunication {

       publicstatic void main(String[] args) {       

              finalBusiness business = new Business();

              newThread(

                            newRunnable() {

                                   @Override

                                   publicvoid run() {

                                  

                                          for(inti=1;i<=50;i++){

                                                 business.sub2(i);

                                          }

                                   }

                            }

              ).start();

              newThread(

                            newRunnable() {

                                  

                                   @Override

                                   publicvoid run() {

                                          for(inti=1;i<=50;i++){

                                                 business.sub3(i);

                                          }

                                   }

                            }

              ).start(); 

              for(inti=1;i<=50;i++){

                     business.main(i);

              }

       }

       staticclass 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) {

                                          e.printStackTrace();

                                   }

                              }

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

                            System.out.println("sub2thread sequence 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("sub3thread sequence 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("mainthread sequence of " + j + ",loop of " + i);

                                   }

                                   shouldSub= 2;

                                   condition2.signal();

                }finally{

                       lock.unlock();

                }

         }

       }

}

 

Semaphore同步工具

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

2.Semaphore 通常用于限制可以访问某些资源的线程数目。

Semphore s = newSemphore(5);

s.acquire();//请求

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

 

CyclicBarrier同步工具

CyclicBarrier 支持一个可选的 Runnable 命令,在一组线程中的最后一个线程到达之后,该命令只在每个屏障点运行一次。若在继续所有参与线程之前更新共享状态。

CyclicBarrier cb= new CyclicBarrier(2);

cb.getNumberWaiting()当前等待个数

cb.await();等待

 

CountDownLatch同步工具

1.倒计时计数器,调用CountDownLatch对象的countDown方法。

2.CountDownLatch 的一个有用特性是,在countDown 方法的所有线程都能通过之前,阻止任何线程继续通过一个await

 

Exchanger同步工具

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

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

Thread.sleep(Random)换的过程

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

 

阻塞队列的应用(ArrayBlockingQueue

1.固定长度的队列往里放数据,如果放满了还要放,阻塞式队列就会等待,直到有数据取出,空出位置后才继续放;非阻塞式队列报错。

2.两个附加操作的Queue:获取元素时等待队列变为非空,以及存储元素时等待空间变得可用。

3.BlockingQueue 方法四种形式

(1)抛出一个异常。

(2)返回一个特殊值(null false,具体取决于操作)。

(3)在操作可以成功前,无限期地阻塞当前线程。

(4)在放弃前只在给定的最大时间限制内阻塞。

示例

public staticvoid main(String[] args) {

final BlockingQueue<Integer> queue =new ArrayBlockingQueue<Integer>(3);

//该队列里面只能放3Integer

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

new Thread(){

public void run(){

while(true){

try {

Thread.sleep((long)(Math.random()*1000));

System.out.println(Thread.currentThread().getName() +"准备放数据!");

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

System.out.println(Thread.currentThread().getName()+ "已经放了数据,"+ "队列目前有" +queue.size() + "个数据");

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}.start();

}

new Thread(){

public void run(){

while(true){

try {

Thread.sleep(1000);

System.out.println(Thread.currentThread().getName() +"准备取数据!");

queue.take();//如果没有了数据,就会阻塞

System.out.println(Thread.currentThread().getName()+ "已经取走数据,"+

"队列目前有" + queue.size() + "个数据");

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}.start();

} 

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