线程并发库

来源:互联网 发布:储存卡损坏数据恢复 编辑:程序博客网 时间:2024/05/18 03:57

线程并发库

  传统线程的使用

       创建线程

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

   定时器

   Timer类

  TimerTask类

package threadTest;import java.util.Date;import java.util.Timer;import java.util.TimerTask;/*需求 爆炸装置.第一次爆炸后4秒爆炸,再相隔2秒爆炸.进行循环 *  * 做法: 定义两个定时器类,分别在类中掉另一个类,当第一个类执行结束会自动执另一个类 */public class TraditionalTimerTest {static int count =0;public static void main(String[] args) {//定时器使用Timer timer = new Timer();timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("big bong");}}, 2000,3000);//定在定时器设定一个变量,让定时器自动循环/*class myTimeTask extends TimerTask{public void run() {count = (count + 1) % 2;System.out.println("bong");new Timer().schedule(new myTimeTask(),2000 + 2000 * count);}}new Timer().schedule(new myTimeTask(), 2000);*///定义两个类相互切换TraditionalTimerTest ttt = new TraditionalTimerTest();new Timer().schedule(ttt.new myTimeTask1(), 2000);while(true){try {Thread.sleep(1000);System.out.println(new Date().getSeconds());} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}class myTimeTask1 extends TimerTask{int count1 = 2000;public void run() {System.out.println("bong");new Timer().schedule(new myTimeTask2(),count1);}}class myTimeTask2 extends TimerTask{int count2 = 4000;public void run() {System.out.println("bong");new Timer().schedule(new myTimeTask1(),count2);}}}

        

           线程同步互斥

          互斥必须使用同一个对象,才能互斥.

          锁是上在代表要操作的资源的类的内部方法中,而不是线程代码中

          要用到共同数据(包括同步锁)或共同算法的若干个方法应该归到同一个类身上,这种设计正好体现了高类聚和程序的健壮性.

package threadTest;/*需求 多线程打印字符串 *  *1.需要使用互斥锁,因为当一段线程执行时会有可能切换到另一个线程,这要就会出现字符串错误 *2.将相同的数据封装到一个类的方法中 *3.2个线程必须使用同一个对象 */public class TraditionalSynchronized {public static void main(String[] args) {new TraditionalSynchronized().init();}public void init(){final Output op = new Output();new Thread(new Runnable(){public void run() {while(true){try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}op.output("llllllllllllllllllll");}};}).start();new Thread(new Runnable(){public void run() {while(true){try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}op.output("mmmmmmmmmmmmmmmmmmmmmmm");}};}).start();}class Output{public void output(String name) {synchronized(this){for(int i=0; i<name.length(); i++){System.out.print(name.charAt(i));}System.out.println();}}}}


            题2:

package threadTest;/*需求 主线程运行100次   子线程运行10次,循环50次 *  * wait方法必须在synchronized中使用 * 向需要同步的方法封装到一个类中 *  * 思路 :  * 1 两个线程要互斥 * 2要有wait进行循环 * 3将需要互斥的方法封装成类 *  * 步骤 * 1建立线程  * 2实现循环 * 3建立互斥的类 *  */public class TraditionalSynchronized2 {static A a = new A();public static void main(String[] args) {new Thread(new Runnable(){@Overridepublic void run() {for(int i=1; i<=50; i++){a.t(i);}}}).start();for(int i=1; i<=50; i++){a.m(i);}}static class A {static boolean bA = true;public synchronized void t(int i){while(!bA){try {this.wait();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}for(int j=1; j<=10; j++){System.out.println("子线程第" + i + "次线程" + j);}bA = !bA;this.notify();}public synchronized void m(int i){while(bA){try {this.wait();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}for(int j=1; j<=100; j++){System.out.println("主线程第" + i + "次main" + j);}bA = !bA;this.notify();}}}

      多线程访问共享数据

      如果每个线程执行的代码相同,可以使用同一个Runnable对象,这个Runnable对象中有那个共享数据.线程里只能有一种动作

  

   如果每个线程执行的代码不同,这时候需要用不同的Runnable对象,有如下两种方式来实现这些Runnable对象之间的数据共享:

       将共享数据封装在另外一个对象中,然后将这个对象逐一传递给各个Runnable对象。每个线程对共享数据的操作方法也分配到那个对象身上去完成,这样容易实现针对该数据进行的各个操作的互斥和通信。

       将这些Runnable对象作为某一个类中的内部类(匿名类),共享数据作为这个外部类中的成员变量,每个线程对共享数据的操作方法也分配给外部类,以便实现对共享数据进行的各个操作的互斥和通信,作为内部类的各个Runnable对象调用外部类的这些方法。

       上面两种方式的组合:将共享数据封装在另外一个对象中,每个线程对共享数据的操作方法也分配到那个对象身上去完成,对象作为这个外部类中的成员变量或方法中的局部变量,每个线程的Runnable对象作为外部类中的成员内部类或局部内部类。

        总之,要同步互斥的几段代码最好是分别放在几个独立的方法中,这些方法再放在同一个类中,这样比较容易实现它们之间的同步互斥和通信。

       极端且简单的方式,即在任意一个类中定义一个static的变量,这将被所有线程共享。


    线程范围内的共享变量

    每个线程调用全局ThreadLocal对象的set方法,就相当于往其内部的map中增加一条记录,key分别是各自的线程,value是各自的set方法传进去的值。在线程结束时可以调用ThreadLocal.clear()方法,这样会更快释放内存,不调用也可以,因为线程结束后也可以自动释放相关的ThreadLocal变量。

    map实现的线程范围内共享

package threadTest;import java.util.HashMap;import java.util.Map;import java.util.Random;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;/*需求 : 线程范围内共享数据 ,有一个数据,在线程内共享,在线程外独立.有一个静态数据,在不同线程内部的值不同.   *  * 思想:  * 1要有多个对象,这些对象会去使用线程中的数据 * 2有多个线程都会使用到这个数据 * 3数据在每个线程的内部的值不同 */public class ThreadScopeShareData {//用static修饰的数据可以实现所有线程都可以使用这个数据,也就是多个线程数据共享//static int data;private static Map<Thread, Integer> map = new HashMap<Thread, Integer>();public static void main(String[] args) {final Lock lock = new ReentrantLock();//实现两个线程for(int i=0; i<2; i++) {new Thread(new Runnable(){@Overridepublic void run() {int data = new Random().nextInt();System.out.println(Thread.currentThread().getName() + "get data :" + data);//lock.lock();map.put(Thread.currentThread(), data);//lock.unlock();new A().getData();new B().getData();}}).start();}}static class A {public void getData() {System.out.println("A from " + Thread.currentThread().getName() + "get data :" + map.get(Thread.currentThread()));}}static class B {public void getData() {System.out.println("B from " + Thread.currentThread().getName() + "get data :" + map.get(Thread.currentThread()));}}}


    ThreadLocal类

     实现对ThreadLocal变量的封装,让外界不要直接操作ThreadLocal变量。

         对基本类型的数据的封装,这种应用相对很少见。

         对对象类型的数据的封装,比较常见,即让某个类针对不同线程分别创建一个独立的实例对象

package threadTest;import java.util.HashMap;import java.util.Map;import java.util.Random;/*需求 : 用ThreadLocal实现线程范围内的数据共享,和多个数据线程范围内共享的封装 *  * 1ThreadLocal相当于一个map,他的key默认为当前线程,并且在每个线程中独立 *  * 2将数据放在一个对象中,并将这个对象放在ThreadLocal里就可以实现多数据的线程内共享 * 3利用类似单例的方法,将ThreadLocal封装到一个对象中, * 并在每个线程中新建当前类的对象,将共享的数据也封装到这个对象里, */public class ThreadLocalTest {private static ThreadLocal<Integer> map = new ThreadLocal<Integer>();public static void main(String[] args) {//实现两个线程共享一个数据for(int i=0; i<2; i++) {new Thread(new Runnable(){@Overridepublic void run() {int data = new Random().nextInt();System.out.println(Thread.currentThread().getName() + "get data :" + data);map.set(data);MyThreadScopeData.getThreadInstance().setName("name" + data);MyThreadScopeData.getThreadInstance().setAge(data);new A().get();new B().get();}}).start();}}static class A {public void get() {int data = map.get();System.out.println("A from " + Thread.currentThread().getName() + "get data :" + data);System.out.println("A from " + Thread.currentThread().getName() + "name: " + MyThreadScopeData.getThreadInstance().getName() + "age: " + MyThreadScopeData.getThreadInstance().getAge());}}static class B {public void get() {int data = map.get();System.out.println("B from " + Thread.currentThread().getName() + "get data :" + data);System.out.println("B from " + Thread.currentThread().getName() + "name: " + MyThreadScopeData.getThreadInstance().getName() + "age: " + MyThreadScopeData.getThreadInstance().getAge());}}}//将多个线程共享数据封装class MyThreadScopeData {private MyThreadScopeData(){}private static ThreadLocal<MyThreadScopeData> local = new ThreadLocal<MyThreadScopeData>();//可以获得当前线程的MyThreadScopeDate对象public static MyThreadScopeData getThreadInstance() {MyThreadScopeData instance = local.get();if(instance == null) { instance = new MyThreadScopeData();local.set(instance);}return instance;}private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}}


   java5中的线程并发库

          线程并发库共有3个包:

         java.util.concurrent

       java.util.concurrent.atomic

       java.util.concurrent.lock


       java.util.concurrent.atomic包是对java中的一些数据进行封装,在这些数据进行操作时不会受到其他线程的干扰

      AtomicInteger类的intaddAndGet(int i,int delta); 对Integer类型进行加减,在加减过程是互斥的

      AtomicIntegerArray类的booleancompareAndSet(expectedValue,updateValue);

      AtomicIntegerFieldUpdater类,对类中的Integer对象进行赋值,


      线程池

      在线程池的编程模式下,任务是提交给整个线程池,而不是直接交给某个线程,线程池在拿到任务后,它就在内部找有无空闲的线程,再把任务交给内部某个空闲的线程,这就是封装。记住,任务是提交给整个线程池,一个线程同时只能执行一个任务,但可以同时向一个线程池提交多个任务。

          在线程池中,如果不用shutdown方法,线程会一直等待新线程而不会自动停止.

package threadTest;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.TimeUnit;/*线程池.固定个数的线程取线程池中的线程,一个线程执行完后会继续等待新线程, *  * 有3种线程池 * 固定个数线程的线程池 : FixedThreadPool    固定线程个数 * 缓存线程池   :CachedThreadPool * 单个线程池: 单个线程池会保证一个线程的永远存在 :SingleThreadExecutor *  * 定时器 * 多线程定时器线程池  ScheduledThreadPool * 单线程定时器 *  */public class ThreadPoolTest {public static void main(String[] args) {//固定线程池:在这里只有3个线程在运行//ExecutorService pool1 = Executors.newFixedThreadPool(3);//缓存线程池,线程数会自动调整//ExecutorService pool1 = Executors.newCachedThreadPool();//单个线程池ExecutorService pool1 = Executors.newSingleThreadExecutor();for(int i=1;i<=10;i++) {final int task = i;pool1.execute(new Runnable() {@Overridepublic void run() {for(int j=1;j<=10;j++) {try {Thread.sleep(20);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(Thread.currentThread().getName() + " is looping of " + j + " for task of " + task);}}});}//关闭线程池pool1.shutdown();//定时器ScheduledExecutorService scheduled = Executors.newScheduledThreadPool(3);scheduled.schedule(new Runnable() {@Overridepublic void run() {System.out.println("big bong");}}, 6, TimeUnit.SECONDS);}}


      Callable&Future

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

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

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

package threadTest;import java.util.concurrent.Callable;import java.util.concurrent.CompletionService;import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorCompletionService;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;/* * Callable 让线程返回结果 *  * CompletionService :提交一组线程返回最先结束的结果 */public class ThreadCallable {public static void main(String[] args) {ExecutorService pool = Executors.newSingleThreadExecutor();Future<String> future = pool.submit(new Callable<String>() {@Overridepublic String call() throws Exception {Thread.sleep(5000);return Thread.currentThread().getName();}});System.out.println("等待结果");try {//获得结果String str = future.get();//固定时间未得到结果自动退出//String str = future.get(1, TimeUnit.SECONDS);System.out.println("结果为" + str);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (ExecutionException e) {// TODO Auto-generated catch blocke.printStackTrace();}//CompletionServiceExecutorService  pool1 = Executors.newFixedThreadPool(10);CompletionService<Integer> completionService = new ExecutorCompletionService<>(pool1);for(int i=0;i<=10;i++) {final int seq = i;completionService.submit(new Callable<Integer>() {@Overridepublic Integer call() throws Exception {return seq;}});}for(int i=0;i<10;i++) {try {System.out.println(completionService.take().get());} catch (InterruptedException | ExecutionException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}

      lock

       Lock比传统线程模型中的synchronized方式更加面向对象,与生活中的锁类似,锁本身也应该是一个对象。两个线程执行的代码片段要实现同步互斥的效果,它们必须用同一个Lock对象

package threadTest;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;/*需求 使用Lock实现互斥 */public class LockTest {public static void main(String[] args) {new LockTest().init();}public void init(){final Output op = new Output();new Thread(new Runnable(){public void run() {while(true){try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}op.output("llllllllllllllllllll");}};}).start();new Thread(new Runnable(){public void run() {while(true){try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}op.output("mmmmmmmmmmmmmmmmmmmmmmm");}};}).start();}class Output{Lock lock = new ReentrantLock();public void output(String name) {lock.lock();try {for(int i=0; i<name.length(); i++){System.out.print(name.charAt(i));}System.out.println();}finally {lock.unlock();}}}}

       读写锁

    读写锁:分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,这是由jvm自己控制的,你只要上好相应的锁即可。如果你的代码只读数据,可以很多人同时读,但不能同时写,那就上读锁;如果你的代码修改数据,只能有一个人在写,且不能同时读取,那就上写锁。总之,读的时候上读锁,写的时候上写锁!

package threadTest;import java.util.Random;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.locks.ReentrantReadWriteLock;/*需求 读写锁 * * 读读不互斥 , 读写互斥, 写写互斥 */public class ReadwriteLockTest {static Data1 data = new Data1();public static void main(String[] args) {ExecutorService exe = Executors.newCachedThreadPool();for(int i=0;i<3;i++) {exe.execute(new Runnable() {@Overridepublic void run() {data.get();}});}for(int i=0;i<3;i++) {exe.execute(new Runnable() {@Overridepublic void run() {data.put(new Random().nextInt());}});}}}class Data1 {private Object data;private ReentrantReadWriteLock rwl= new ReentrantReadWriteLock();void get() {rwl.readLock().lock();try {System.out.println(Thread.currentThread().getName() + "开始读数据");try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println("读数据完毕,数据是: " + data);}finally {rwl.readLock().unlock();}}void put(Object obj) {rwl.writeLock().lock();try {System.out.println(Thread.currentThread().getName() + "开始写数据");try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}data = obj;System.out.println("写数据完毕,数据是: " + data);}finally {rwl.writeLock().unlock();}}}


    读写锁的取缓存中数据的应用
  

 load(String key) {rwl.readLock.lock();try{Object obj = data.get(key);  if(key == null) {  rwl.readLock.unlock();  rwl.writeLock.lock();    //第二次判断,当多线程运行时,第一个写锁取完数据后就不再取数据了  for(key == null) {  //从服务器里拿key的值  }  rwl.readLock.lock();  rwl.writeLock.unlock();  }  }finaly {  rwl.readLock.unloc();  }      }


         condition阻塞

        一个锁内部可以有多个Condition,即有多路等待和通知,可以参看jdk1.5提供的LockCondition实现的可阻塞队列的应用案例,从中除了要体味算法,还要体味面向对象的封装。在传统的线程机制中一个监视器对象上只能有一路等待和通知,要想实现多路等待和通知,必须嵌套使用多个同步监视器对象.

     condition必须在Lock里.一个Lock下可有多个condition,多个condition在多个线程下.

package threadTest;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;/*需求 : 使用condition实现主线程运行100次   子线程运行10次,第2子线程运行20次,循环50次 */public class ConditionTest {static A a = new A();public static void main(String[] args) {new Thread(new Runnable(){@Overridepublic void run() {for(int i=1; i<=50; i++){a.sub2(i);}}}).start();new Thread(new Runnable(){@Overridepublic void run() {for(int i=1; i<=50; i++){a.shu1(i);}}}).start();for(int i=1; i<=50; i++){a.m(i);}}static class A {private Lock lock = new ReentrantLock();private Condition condition1 = lock.newCondition();private Condition condition2 = lock.newCondition();private Condition condition3 = lock.newCondition();private int should = 1;public void sub2(int i){lock.lock();try {while(should != 3){try {condition3.await();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}for(int j=1; j<=20; j++){System.out.println("sub2线程第" + i + "次线程" + j);}should = 1;condition1.signal();}finally {lock.unlock();}}public void shu1(int i){lock.lock();try {while(should != 2){try {condition2.await();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}for(int j=1; j<=10; j++){System.out.println("sub1线程第" + i + "次线程" + j);}should = 3;condition3.signal();}finally {lock.unlock();}}public synchronized void m(int i){lock.lock();try {while(should != 1){try {condition1.await();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}for(int j=1; j<=100; j++){System.out.println("main线程第" + i + "次" + j);}should = 2;condition2.signal();}finally {lock.unlock();}}}}


       用condition写链表

package threadTest;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;/*需求 用array链表,有condition实现阻塞,实现存取数据的方法 *  */public class ConditionLinked {public static void main(String[] args) {final ConditionLinked cl = new ConditionLinked();ExecutorService exe = Executors.newCachedThreadPool();exe.execute(new Runnable() {@Overridepublic void run() {for(int i=0; i<1000; i++) {try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}cl.put(i);}}});exe.execute(new Runnable() {@Overridepublic void run() {while(true) {try {Thread.sleep(1);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}cl.take();}}});}private Object[] data = new Object[100];private int count, putper, takeper;private Lock lock = new ReentrantLock();private Condition conditionPut = lock.newCondition();private Condition conditionTake = lock.newCondition();public void put(Object obj) {lock.lock();try {System.out.println(Thread.currentThread().getName() + "开始put");while(count == data.length) {System.out.println("put开始等待");try {conditionPut.await();System.out.println("put等待结束");} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}if(putper == data.length)putper = 0;data[putper] = obj;putper++;count++;conditionTake.signal();System.out.println(obj + "存入完毕!");}finally {lock.unlock();}}public Object take() {lock.lock();Object obj;System.out.println(Thread.currentThread().getName() + "开始取数据");try{while(count == 0) {try {System.out.println("take开始等待");conditionTake.await();System.out.println("take等待结束");} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}if(takeper == data.length)takeper = 0;obj = data[takeper];takeper++;count--;conditionPut.signal();System.out.println("take将" + obj + "取走");}finally {lock.unlock();}return null;}}


     同步器

    Semaphore:信号灯

    Semaphore的作用类似Lock的功能,不同的是Semaphore的构造函数中可以传入一个int型的参数,用来确定创建一个多大的通道。

    Lock一次只允许一个线程进入,解锁后才允许别的线程进入。而Semaphore可以允许多个线程同时进入,一旦有线程释放就会空出一个位置让另外的线程进入。

   Semaphore可以维护当前访问自身的线程个数,并提供了同步机制。使用Semaphore可以控制同时访问资源的线程个数,例如,实现一个文件允许的并发访问数。

 单个信号量的Semaphore对象可以实现互斥锁的功能,并且可以是由一个线程获得了“锁”,再由另一个线程释放“锁”,这可应用于死锁恢复的一些场合。


package threadTest;import java.util.Random;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Semaphore;public class SemaphoreTest {public static void main(String[] args) {final Semaphore semaphore = new Semaphore(3, true);ExecutorService service = Executors.newCachedThreadPool();for(int i=0;i<10;i++) {Runnable runnable = new Runnable() {@Overridepublic void run() {try {semaphore.acquire();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}try{System.out.println(Thread.currentThread().getName() + "开始获取线程,现在共有" + (3 - semaphore.availablePermits()) + "个线程并发");try {Thread.sleep(new Random().nextInt(5000));} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(Thread.currentThread().getName() + "运行结束");}finally {semaphore.release();}System.out.println(Thread.currentThread().getName() + "运行结束,共有" + (3 - semaphore.availablePermits()) + "个线程并发");}};service.execute(runnable);}}}


  CyclicBArrier 障碍

  是一个可重置的同步锁.

   当所有设置的线程都到阻塞点时,才解锁.

package threadTest;import java.util.Random;import java.util.concurrent.BrokenBarrierException;import java.util.concurrent.CyclicBarrier;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/* * CyckicBarrier的使用 参数为线程个数 */public class CyclicBarrierTest {public static void main(String[] args) {ExecutorService service = Executors.newCachedThreadPool();final CyclicBarrier cb = new CyclicBarrier(3);for(int i=0;i<3;i++) {Runnable command = new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "开始运行");try {Thread.sleep(new Random().nextInt(5000));} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(Thread.currentThread().getName() + "到达第一个阻塞点");try {cb.await();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (BrokenBarrierException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(Thread.currentThread().getName() + "通过第一个阻塞点");try {Thread.sleep(new Random().nextInt(5000));} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(Thread.currentThread().getName() + "到达第二个阻塞点");try {cb.await();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (BrokenBarrierException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(Thread.currentThread().getName() + "通过第二个阻塞点");try {Thread.sleep(new Random().nextInt(5000));} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(Thread.currentThread().getName() + "到达第三个阻塞点");try {cb.await();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (BrokenBarrierException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(Thread.currentThread().getName() + "通过第三个阻塞点");}};service.execute(command);}}}


   CountDownLatch定时器

   犹如倒计时计数器,调用CountDownLatch对象的countDown方法就将计数器减1,当计数到达0时,则所有等待者或单个等待者开始执行。

 当阻塞值为0时才执行

package threadTest;import java.util.concurrent.CountDownLatch;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/*CountDownLatch的使用,定时器 */public class CountDownLatchTest {public static void main(String[] args) {ExecutorService service = Executors.newCachedThreadPool();final CountDownLatch countMain = new CountDownLatch(3);final CountDownLatch countSub = new CountDownLatch(1);for(int i=0;i<3;i++) {service.execute(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "开始执行");try {countSub.await();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(Thread.currentThread().getName() + "通过阻塞");try {Thread.sleep((long) (Math.random() * 5000));} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}countMain.countDown();System.out.println(Thread.currentThread().getName() + "线程结束");}});}System.out.println("main方法");try {Thread.sleep((long) (Math.random() * 5000));} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}countSub.countDown();System.out.println("main方法开始阻塞");try {countMain.await();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println("main方法执行完毕");}}


  Exchanger 数据交换

  用于实现两个人之间的数据交换,每个人在完成一定的事务后想与对方交换数据,第一个先拿出数据的人将一直等待第二个人拿着数据到来时,才能彼此交换数据。

package threadTest;import java.util.concurrent.Exchanger;public class ExchangerTest {public static void main(String[] args) {final Exchanger ex = new Exchanger();new Thread(new Runnable() {@Overridepublic void run() {String data = "mmmmmmmm";String data2 = null;System.out.println(Thread.currentThread().getName() + "的数据是" + data);try {Thread.sleep(5000);} catch (InterruptedException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}try {data2 = (String)ex.exchange(data);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(Thread.currentThread().getName() + "结果是" + data2);}}).start();new Thread(new Runnable() {@Overridepublic void run() {String data = "lllllllllllll";String data2 = null;System.out.println(Thread.currentThread().getName() + "的数据是" + data);try {data2 = (String)ex.exchange(data);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(Thread.currentThread().getName() + "结果是" + data2);}}).start();}}


    可阻塞队列

   阻塞队列与Semaphore有些相似,但也不同,阻塞队列是一方存放数据,另一方释放数据,Semaphore通常则是由同一方设置和释放信号量。

   只有put方法和take方法才具有阻塞功能

package threadTest;import java.util.concurrent.ArrayBlockingQueue;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/*使用阻塞队列  *  */public class ArrayBlockingQueueTest {public static void main(String[] args) {final ArrayBlockingQueue<Integer> abq = new ArrayBlockingQueue<Integer>(3);ExecutorService exe = Executors.newCachedThreadPool();exe.execute(new Runnable() {@Overridepublic void run() {for(int i=0; i<1000; i++) {System.out.println(Thread.currentThread().getName() + "开始存数据");try {Thread.sleep(100);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}try {abq.put(i);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println(Thread.currentThread().getName() + "存数据" + i + "完毕");}}});exe.execute(new Runnable() {@Overridepublic void run() {while(true) {System.out.println(Thread.currentThread().getName() + "开始拿数据");try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}try {Integer data = abq.take();System.out.println(Thread.currentThread().getName() + "拿数据完毕,数据: " + data);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}});}}

    用两个具有1个空间的队列来实现同步通知的功能

package threadTest;import java.util.concurrent.ArrayBlockingQueue;public class QueueTest {static A a = new A();public static void main(String[] args) {new Thread(new Runnable(){@Overridepublic void run() {for(int i=1; i<=50; i++){a.t(i);}}}).start();for(int i=1; i<=50; i++){a.m(i);}}static class A {ArrayBlockingQueue<Integer> arr1 = new ArrayBlockingQueue<Integer>(1); ArrayBlockingQueue<Integer> arr2 = new ArrayBlockingQueue<Integer>(1); {try {arr1.put(1);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}public void t(int i){try {arr1.put(1);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}for(int j=1; j<=10; j++){System.out.println("第" + i + "次线程" + j);}try {arr2.take();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}public void m(int i){try {arr2.put(1);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}for(int j=1; j<=100; j++){System.out.println("第" + i + "次main" + j);}try {arr1.take();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}

         同步集合

       传统方式下用Collections工具类提供的synchronizedCollection方法来获得同步集合。
    传统方式下的Collection在迭代集合时,不允许对集合进行修改。
        Java5中提供了如下一些同步集合类:
ConcurrentHashMap
CopyOnWriteArrayList
CopyOnWriteArraySet
     使用同步集合可以保证多线程中的集合数据的同步,不会发生死循环.并且可以在序列化中动态的删除数据.






0 0