http://wangjianwei866.blog.163.com/blog/static/9295823201231665319314/
基于以上网文,调整了一下格式,修改了一些标点和拼写错误。
在实际应用中,经常用到线程的并发,那为什么需要用到并发呢,不能独自单独的程序处理吗,那很明确的说,多条线程做完成一件事情和一条线程去完成一件事情,那是无法同言而语的。比如在实际的网站访问过程中,世界各地的人都去同事访问一个网站,在服务器端,如果收到一个请求就对它先处理,而其他用户的请求到达只是对 他们先存储,然后在对他们进行处理,可想而知这样的速度会有多慢,如果一天之类用千万级的用户访问,那样的速度无法想象。在现实生活中这样的例子随处可见,做 一件事情,一个人去做和多个人同事做可想这样的速度是多么快,只是在做的过程当中对与大家共用的东西应当控制并发访问问题。
当线程并发的时候,随之而来的也带来了一些问题,如果多条线程去同时操作共享而用的数据那将是会使共享的数据很容易就出现错误。在JAVA中提供同防止多条线程同时共享数据的方式是:synchronized,volatile很好的利用这两个关键字就能防止并发而带来的问题,同时在JAVA1.5之后也提供了更多好用的类来解决这个问题
当有许多请求需要去处理的时候,如果只是单独的一个人去处理,可想而知那会让后面在排队的人等多久,这样就需要线程池,有请求过来了就到线程池里 面取出一条线程去处理它,处理完成就把它收回到线程池里面,然而自己实现 一个功能强大的线程池也并非易事,在java1.5之后专门提供了线程池的类库
submit(Callable<T> task); submit(Runnable task) submit(Runnable task, T result) execute()说明:前三个方法都是带有返回值的执行任务,最后一个方法只是单纯的执行任务,方法的返回值是Future类型的,它是支持泛型的,返回值要和泛型的类型一致
Future<String> future = service.submit(new Callable<String>() { Public String call() throws Exception() { Return “test”; } });
在单位时间内执行任务
public static void main5() { ScheduledExecutorService service = Executors.newScheduledThreadPool(4); System.out.println("5秒钟后将发生爆炸"); service.schedule(new Callable<String>() { @Override public String call() throws Exception { System.out.println("蹦............"); return "success"; } }, 5, TimeUnit.SECONDS); }
public static void main7() { ScheduledExecutorService service = Executors.newScheduledThreadPool(4); System.out.println("5秒钟后将发生连环爆炸"); service.scheduleWithFixedDelay((new Runnable() { @Override public void run() { System.out.println("蹦..........."); } }), 5, 1, TimeUnit.SECONDS); }scheduleWithFixedDelay或者scheduleAtFixedRate方法都是能够产生循环定时器,只是实现方式不一样
ExecutorService service = Executors.newSingleThreadExecutor();
ExecutorCompletionService 用它来执行任务,所有任务的返回结果都将放置在一个队列上,之后可以通过队列取得任务的执行结果,根据任务执行结果做相应的操作,同时也很方便的对所有的执行结果统一的处理
public static void main8() { ExecutorService service = Executors.newCachedThreadPool(); CompletionService<Integer> cservice = new ExecutorCompletionService<Integer>(service); Collection<Callable<Integer>> tasks = new ArrayList<Callable<Integer>>(); for (int i = 0; i < 10; i++) { final int squence = i; tasks.add(new Callable<Integer>() { @Override public Integer call() throws Exception { for (int j = 1; j < 5; j++) { System.out.println(Thread.currentThread().getName() + " task " + squence + " time " + j); } return squence; } }); } for (Callable<Integer> task : tasks) { cservice.submit(task); } //统一处理任务结果 int result = 0; for (int i = 0; i < tasks.size(); i++) { result += cservice.take().get(); } System.out.println(result); }
可知任务完成的时候,处理结果会存放在调用take()方法所获取的队列上面,方便统一处理结果
锁是用来防止线程并发而带来的线程安全问题,在访问线程共享数据的时候,操作它或者读取它的时候,如果不希望别的线程也同时对它就行读取,那应该给它上锁,这样只要一个线程进去了对他上锁了,别的线程就无法在进入了。有时候线程并发不是就是单一并发访问问题,并发访问同时可能也会导致数据不一致
public class LockTest { public static void main(String[] args) { final Service s = new Service(); ExecutorService service = Executors.newCachedThreadPool(); for (int i = 0; i < 10; i++) { service.execute(new Runnable() { public void run() { s.service(); } }); } } static class Service { private int count = 0; Lock lock = new ReentrantLock(); public void service() { ++count; try { Thread.sleep(200l); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("service :" + count + " time"); } } }
对与以上程序,我们希望打印的是
service : 1 timepublic void service() { try { lock.lock();//加锁 ++count; Thread.sleep(200l); System.out.println("service :" + count + " time"); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock();//释放锁 } }
在JDK5.0以前是没用线程并发库的,如果用synchronized确实能实现同步问题,但是比如对与一个类的属性,希望的效果是在读取它的时候能多线程同时读,在写它的时候不能读,在读它的时候不能写。这样如果只是单单在方法上面加synchronized关键字,它会使所有的线程互斥,不能说多个线程能同时读取对象的值,虽然自己编写代码实现,但是JAVA5之后线程并发库已经给了解决方案,那就是读写锁,如下例子:
public class LockTest { public static void main(String[] args) { final ReadWriteLockT s = new ReadWriteLockT(); ExecutorService service = Executors.newCachedThreadPool(); for (int i = 0; i < 4; i++) { service.execute(new Runnable() { public void run() { while (true) { s.getX(); } } }); service.execute(new Runnable() { public void run() { while (true) { s.setX(new Random().nextInt()); } } }); } } static class ReadWriteLockT { private int x = 0; private ReadWriteLock rock = new ReentrantReadWriteLock(); public void setX(int x) { rock.writeLock().lock(); System.out.println(Thread.currentThread().getName() + ".........进入写读锁"); this.x = x; try { Thread.sleep(200L); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("写完毕"); rock.writeLock().unlock(); } public int getX() { rock.readLock().lock(); System.out.println(Thread.currentThread().getName() + "----------进入读读锁:"); try { Thread.sleep(500L); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(x); System.out.println("读完毕"); rock.readLock().unlock(); return x; } } }
class BoundedBuffer { final Lock lock = new ReentrantLock(); final Condition notFull = lock.newCondition(); final Condition notEmpty = lock.newCondition(); final Object[] items = new Object[100]; int putptr, takeptr, count; public void put(Object x) throws InterruptedException { lock.lock(); try { while (count == items.length) notFull.await(); items[putptr] = x; if (++putptr == items.length) putptr = 0; ++count; notEmpty.signal(); } finally { lock.unlock(); } } public Object take() throws InterruptedException { lock.lock(); try { while (count == 0) notEmpty.await(); Object x = items[takeptr]; if (++takeptr == items.length) takeptr = 0; --count; notFull.signal(); return x; } finally { lock.unlock(); } } }
class MyDate { private int volatile x; public void opera() { x++; } }
package com.moom; import java.util.Random; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; public class BlockingDequeTest { public static void main(String[] args) { final BlockingQueue<String> queue = new LinkedBlockingQueue<String>(6);//创建一个只能容纳6个容量的阻塞队列 ExecutorService service = Executors.newCachedThreadPool(); for (int i = 0; i < 3; i++) { //生产三条拿的线程 service.execute(new Runnable() { public void run() { try { while (true) {//不停的拿 Thread.sleep(200l); System.out.println(Thread.currentThread().getName() + "即将拿"); String s = queue.take(); System.out.println(Thread.currentThread().getName() + "拿到" + s); } } catch (InterruptedException e) { e.printStackTrace(); } } }); } while (true) { //不停的放 try { System.out.println(Thread.currentThread().getName() + "即将放"); String s = String.valueOf(new Random().nextInt(10000)); queue.put(s); System.out.println(Thread.currentThread().getName() + "放入了" + s); } catch (InterruptedException e) { e.printStackTrace(); } } } }
有些多线程需要在多条线程完成了相应的事情之后然后就继续去完成后续的事情,每次都是这样,就是说当只有一条线程完成了对应的事情时,他是无法继续向前运行的,只有等待。
例子:package com.moom; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class CyclicBarrierTest { public static void main(String[] args) throws Exception { final CyclicBarrier barrier = new CyclicBarrier(5); ExecutorService service = Executors.newCachedThreadPool(); for (int i = 0; i < 5; i++) { service.execute(new Runnable() { @Override public void run() { // 每条线程要执行的任务 System.out.println("线程" + Thread.currentThread().getName() + "将执行完任务"); try { barrier.await();// 线程执行完就等待,要五条线程都执行完才能做后续操作 // 执行后续任务 System.out.println("线程" + Thread.currentThread().getName() + "后续任务执行完毕"); barrier.await();//等待所有线程执行完后续任务 //执行最后任务,随意执行不等待,结束 } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } }); } service.shutdown(); } }
对与有些多线程共享的数据,并不是说一条线程访问的时候其它线程就不能访问了,是规定只有多少条线程可以访问,好比一个房间里面只能容纳多少个人,只要没满的时候其它的线程就可以进去
例子:package com.moom; 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 se = new Semaphore(5);//创建同时可以五个线程访问控制器 ExecutorService service = Executors.newCachedThreadPool(); for (int i = 0; i < 20; i++) { service.execute(new Runnable() { public void run() { try { se.acquire(); System.out.println("线程" + Thread.currentThread().getName() + "进来了开始执行任务"); Thread.sleep(100l); System.out.println("线程" + Thread.currentThread().getName() + "将要执行完毕"); se.release(); } catch (InterruptedException e) { e.printStackTrace(); } } }); } service.shutdown(); } }
有的多线程应用场景,一个线程唤醒多条线程,多条线程执行完毕有去唤醒这一条线程,就这个循环的唤醒或者单独的唤醒运用用CountDownLatch就比较方便的实现
例子场景:在各类运动比赛当中,裁判线程监视这所有的参赛人线程,参赛人也会监视裁判线程,当裁判说开始参赛人线程开始,参赛人比赛完成,裁判在做回应package com.moom; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class CountDownLatchTest { public static void main(String[] args) { final CountDownLatch judje = new CountDownLatch(1);//产生一个裁判线程用 final CountDownLatch members = new CountDownLatch(5);//5个队员 ExecutorService service = Executors.newCachedThreadPool(); for (int i = 0; i < 5; i++) { service.execute(new Runnable() { public void run() { try { Thread.sleep(10l); System.out.println(Thread.currentThread().getName() + "队员等待下命令"); judje.await();//等待裁判说开始 System.out.println(Thread.currentThread().getName() + "队员开始了"); //执行逻辑 members.countDown();//执行完成 System.out.println(Thread.currentThread().getName() + "结束"); } catch (InterruptedException e) { e.printStackTrace(); } } }); } System.out.println(Thread.currentThread().getName() + "裁判即将通知开始"); try { Thread.sleep(2000l); System.out.println("开始"); judje.countDown(); members.await();//等待所有队员执行完 Thread.sleep(1000l); System.out.println("裁判统计结果"); service.shutdown(); } catch (InterruptedException e) { e.printStackTrace(); } } }
有些线程同步需要互相交换数据,比如两天线程执行完毕之后需要交换完毕的数据用exchanger的可以方便的实现
例子实现:package com.moom; import java.util.concurrent.Exchanger; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ExchangerTest { public static void main(String[] args) { final Exchanger<String> ex = new Exchanger<String>(); final Exchanger<String> ex2 = new Exchanger<String>(); ExecutorService service = Executors.newSingleThreadExecutor(); service.execute(new Runnable() { public void run() { try { Thread.sleep(100l); String da1 = "aaaa"; System.out.println(Thread.currentThread().getName() + "要交换的数据是:" + da1); String end = ex.exchange(da1); System.out.println("正在执行交换"); System.out.println(Thread.currentThread().getName() + "得到的数据是:" + end); } catch (InterruptedException e) { e.printStackTrace(); } } }); try { Thread.sleep(100l); String da1 = "bbbbb"; System.out.println(Thread.currentThread().getName() + "要交换的数据是:" + da1); String end = ex.exchange(da1); System.out.println("正在执行交换"); System.out.println(Thread.currentThread().getName() + "得到的数据是:" + end); } catch (InterruptedException e) { e.printStackTrace(); } } }