线程并发库
来源:互联网 发布:储存卡损坏数据恢复 编辑:程序博客网 时间: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要采用ExecutorSevice的submit方法提交,返回的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提供的Lock与Condition实现的可阻塞队列的应用案例,从中除了要体味算法,还要体味面向对象的封装。在传统的线程机制中一个监视器对象上只能有一路等待和通知,要想实现多路等待和通知,必须嵌套使用多个同步监视器对象.
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可以控制同时访问资源的线程个数,例如,实现一个文件允许的并发访问数。
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();}}}}
同步集合
- java5线程并发库
- 线程并发库----Executors
- java线程并发库
- java线程并发库
- 线程并发库
- Java线程并发库
- java5 线程并发库
- 7、线程并发库
- 【java并发】线程并发库的使用
- 线程并发库(创建线程、守护线程、暂停线程)
- Java线程并发库之线程池
- Java线程通信和线程并发库
- 线程并发库<二>_线程池
- java线程并发库总结
- 线程并发库之---Queue
- 黑马程序员---线程并发库
- 多线程及线程并发库
- 线程并发库之Executors
- 笔试 - 高德软件有限公司python试题 及 答案
- linux 下显示隐藏文件夹
- HEVC标准概览
- Java中的可变类和不可变类
- 学习笔记:数据结构(二)栈与队列
- 线程并发库
- 安装全局钩子程序(鼠标钩子)
- 《c++ primer》学习笔记 第四章 数组与指针
- 设计模式1——Abstract Factory模式(C++实现)
- 21天战拖记——Day6:复习阶段性完成!(2014-05-09)
- 交换排序:快速排序
- 如何卸载Chrome应用程序
- 石子合并(区间dp)
- HDMI热插拔检测原理