当前位置: 首页 > news >正文

门户网站建设工作情况汇报wordpress 下载受限

门户网站建设工作情况汇报,wordpress 下载受限,网站导航栏字体,python基础教程入门JUC 前言#xff1a; 在Java中#xff0c;线程部分是一个重点#xff0c;本篇文章说的JUC也是关于线程的。JUC就是java.util .concurrent工具包的简称。这是一个处理线程的工具包#xff0c;JDK 1.5开始出现的。下面一起来看看它怎么使用。 一、volatile关键字与内存可见…JUC 前言 在Java中线程部分是一个重点本篇文章说的JUC也是关于线程的。JUC就是java.util .concurrent工具包的简称。这是一个处理线程的工具包JDK 1.5开始出现的。下面一起来看看它怎么使用。 一、volatile关键字与内存可见性 1、内存可见性 先来看看下面的一段代码 public class TestVolatile {public static void main(String[] args){ //这个线程是用来读取flag的值的ThreadDemo threadDemo new ThreadDemo();Thread thread new Thread(threadDemo);thread.start();while (true){if (threadDemo.isFlag()){System.out.println(主线程读取到的flag threadDemo.isFlag());break;}}} }Data class ThreadDemo implements Runnable{ //这个线程是用来修改flag的值的public boolean flag false;Overridepublic void run() {try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}flag true;System.out.println(ThreadDemo线程修改后的flag isFlag());} }这段代码很简单就是一个ThreadDemo类继承Runnable创建一个线程。它有一个成员变量flag为false然后重写run方法在run方法里面将flag改为true同时还有一条输出语句。然后就是main方法主线程去读取flag。如果flag为true就会break掉while循环否则就是死循环。按道理下面那个线程将flag改为true了主线程读取到的应该也是true循环应该会结束。看看运行结果 从图中可以看到该程序并没有结束也就是死循环。说明主线程读取到的flag还是false可是另一个线程明明将flag改为true了而且打印出来了这是什么原因呢这就是内存可见性问题。 内存可见性问题当多个线程操作共享数据时彼此不可见。 看下图理解上述代码 要解决这个问题可以加锁。如下 while (true){synchronized (threadDemo){if (threadDemo.isFlag()){System.out.println(主线程读取到的flag threadDemo.isFlag());break;}}}加了锁就可以让while循环每次都从主存中去读取数据这样就能读取到true了。但是一加锁每次只能有一个线程访问当一个线程持有锁时其他的就会阻塞效率就非常低了。不想加锁又要解决内存可见性问题那么就可以使用volatile关键字。 2、volatile关键字 用法 volatile关键字当多个线程操作共享数据时可以保证内存中的数据可见。用这个关键字修饰共享数据就会及时的把线程缓存中的数据刷新到主存中去也可以理解为就是直接操作主存中的数据。所以在不使用锁的情况下可以使用volatile。如下 public volatile boolean flag false;这样就可以解决内存可见性问题了。 volatile和synchronized的区别 volatile不具备互斥性(当一个线程持有锁时其他线程进不来这就是互斥性)。 volatile不具备原子性。 二、原子性 1、理解原子性 上面说到volatile不具备原子性那么原子性到底是什么呢先看如下代码 public class TestIcon {public static void main(String[] args){AtomicDemo atomicDemo new AtomicDemo();for (int x 0;x 10; x){new Thread(atomicDemo).start();}} }class AtomicDemo implements Runnable{private int i 0;public int getI(){return i;}Overridepublic void run() {try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(getI());} }这段代码就是在run方法里面让i然后启动十个线程去访问。看看结果 可以发现出现了重复数据。明显产生了多线程安全问题或者说原子性问题。所谓原子性就是操作不可再细分而i操作分为读改写三步如下 int temp i; i i1; i temp;所以i明显不是原子操作。上面10个线程进行i时内存图解如下 看到这里好像和上面的内存可见性问题一样。是不是加个volatile关键字就可以了呢其实不是的因为加了volatile只是相当于所有线程都是在主存中操作数据而已但是不具备互斥性。比如两个线程同时读取主存中的0然后又同时自增同时写入主存结果还是会出现重复数据。 2、原子变量 JDK 1.5之后Java提供了原子变量在java.util.concurrent.atomic包下。原子变量具备如下特点 有volatile保证内存可见性。用CAS算法保证原子性。 3、CAS算法 CAS算法是计算机硬件对并发操作共享数据的支持CAS包含3个操作数 内存值V预估值A更新值B 当且仅当VA时才会把B的值赋给V即V B否则不做任何操作。就上面的i问题CAS算法是这样处理的首先V是主存中的值0然后预估值A也是0因为此时还没有任何操作这时VB所以进行自增同时把主存中的值变为1。如果第二个线程读取到主存中的还是0也没关系因为此时预估值已经变成1V不等于A所以不进行任何操作。 4、使用原子变量改进i问题 原子变量用法和包装类差不多如下 //private int i 0;AtomicInteger i new AtomicInteger();public int getI(){return i.getAndIncrement();}只改这两处即可。 三、锁分段机制 JDK 1.5之后在java.util.concurrent包中提供了多种并发容器类来改进同步容器类的性能。其中最主要的就是ConcurrentHashMap。 1、ConcurrentHashMap ConcurrentHashMap就是一个线程安全的hash表。我们知道HashMap是线程不安全的Hash Table加了锁是线程安全的因此它效率低。HashTable加锁就是将整个hash表锁起来当有多个线程访问时同一时间只能有一个线程访问并行变成串行因此效率低。所以JDK1.5后提供了ConcurrentHashMap它采用了锁分段机制。 如上图所示ConcurrentHashMap默认分成了16个segment每个Segment都对应一个Hash表且都有独立的锁。所以这样就可以每个线程访问一个Segment就可以并行访问了从而提高了效率。这就是锁分段。但是java 8 又更新了不再采用锁分段机制也采用CAS算法了。 2、用法: java.util.concurrent包还提供了设计用于多线程上下文中的 Collection 实现 ConcurrentHashMap、ConcurrentSkipListMap、ConcurrentSkipListSet、CopyOnWriteArrayList 和 CopyOnWriteArraySet。当期望许多线程访问一个给 定 collection 时ConcurrentHashMap 通常优于同步的 HashMap ConcurrentSkipListMap 通常优于同步的 TreeMap。当期望的读数和遍历远远 大于列表的更新数时CopyOnWriteArrayList 优于同步的 ArrayList。下面看看部分用法 public class TestConcurrent {public static void main(String[] args){ThreadDemo2 threadDemo2 new ThreadDemo2();for (int i0;i10;i){new Thread(threadDemo2).start();}} } //10个线程同时访问 class ThreadDemo2 implements Runnable{private static ListString list Collections.synchronizedList(new ArrayList());//普通做法static {list.add(aaa);list.add(bbb);list.add(ccc);}Overridepublic void run() {IteratorString iterator list.iterator();while (iterator.hasNext()){System.out.println(iterator.next());//读list.add(ddd);//写}} }10个线程并发访问这个集合读取集合数据的同时再往集合中添加数据。运行这段代码会报错并发修改异常。 将创建集合方式改成 private static CopyOnWriteArrayListString list new CopyOnWriteArrayList();这样就不会有并发修改异常了。因为这个是写入并复制每次生成新的所以如果添加操作比较多的话开销非常大适合迭代操作比较多的时候使用。 四、闭锁 java.util.concurrent包中提供了多种并发容器类来改进同步容器的性能。ContDownLatch是一个同步辅助类在完成某些运算时只有其他所有线程的运算全部完成当前运算才继续执行这就叫闭锁。看下面代码 public class TestCountDownLatch {public static void main(String[] args){LatchDemo ld new LatchDemo();long start System.currentTimeMillis();for (int i 0;i10;i){new Thread(ld).start();}long end System.currentTimeMillis();System.out.println(耗费时间为(end - start)秒);} }class LatchDemo implements Runnable{private CountDownLatch latch;public LatchDemo(){}Overridepublic void run() {for (int i 0;i5000;i){if (i % 2 0){//50000以内的偶数System.out.println(i);}}} }这段代码就是10个线程同时去输出5000以内的偶数然后在主线程那里计算执行时间。其实这是计算不了那10个线程的执行时间的因为主线程与这10个线程也是同时执行的可能那10个线程才执行到一半主线程就已经输出“耗费时间为x秒”这句话了。所有要想计算这10个线程执行的时间就得让主线程先等待等10个分线程都执行完了才能执行主线程。这就要用到闭锁。看如何使用 public class TestCountDownLatch {public static void main(String[] args) {final CountDownLatch latch new CountDownLatch(10);//有多少个线程这个参数就是几LatchDemo ld new LatchDemo(latch);long start System.currentTimeMillis();for (int i 0; i 10; i) {new Thread(ld).start();}try {latch.await();//这10个线程执行完之前先等待} catch (InterruptedException e) {}long end System.currentTimeMillis();System.out.println(耗费时间为 (end - start));} }class LatchDemo implements Runnable {private CountDownLatch latch;public LatchDemo(CountDownLatch latch) {this.latch latch;}Overridepublic void run() {synchronized (this) {try {for (int i 0; i 50000; i) {if (i % 2 0) {//50000以内的偶数System.out.println(i);}}} finally {latch.countDown();//每执行完一个就递减一个}}} }如上代码主要就是用latch.countDown()和latch.await()实现闭锁详细请看上面注释即可。 五、创建线程的方式 — 实现Callable接口 直接看代码 public class TestCallable {public static void main(String[] args){CallableDemo callableDemo new CallableDemo();//执行callable方式需要FutureTask实现类的支持用来接收运算结果FutureTaskInteger result new FutureTask(callableDemo);new Thread(result).start();//接收线程运算结果try {Integer sum result.get();//当上面的线程执行完后才会打印结果。跟闭锁一样。所有futureTask也可以用于闭锁System.out.println(sum);} catch (Exception e) {e.printStackTrace();}} }class CallableDemo implements CallableInteger{Overridepublic Integer call() throws Exception {int sum 0;for (int i 0;i100;i){sum i;}return sum;} }现在Callable接口和实现Runable接口的区别就是Callable带泛型其call方法有返回值。使用的时候需要用FutureTask来接收返回值。而且它也要等到线程执行完调用get方法才会执行也可以用于闭锁操作。 六、Lock同步锁 在JDK1.5之前解决多线程安全问题有两种方式(sychronized隐式锁) 同步代码块 同步方法 在JDK1.5之后出现了更加灵活的方式(Lock显式锁) 同步锁 Lock需要通过lock()方法上锁通过unlock()方法释放锁。为了保证锁能释放所有unlock方法一般放在finally中去执行。 再来看一下卖票案例 public class TestLock {public static void main(String[] args) {Ticket td new Ticket();new Thread(td, 窗口1).start();new Thread(td, 窗口2).start();new Thread(td, 窗口3).start();} }class Ticket implements Runnable {private int ticket 100;Overridepublic void run() {while (true) {if (ticket 0) {try {Thread.sleep(200);} catch (Exception e) {}System.out.println(Thread.currentThread().getName() 完成售票余票为 (--ticket));}}} }多个线程同时操作共享数据ticket所以会出现线程安全问题。会出现同一张票卖了好几次或者票数为负数的情况。以前用同步代码块和同步方法解决现在看看用同步锁怎么解决。 class Ticket implements Runnable {private Lock lock new ReentrantLock();//创建lock锁private int ticket 100;Overridepublic void run() {while (true) {lock.lock();//上锁try {if (ticket 0) {try {Thread.sleep(200);} catch (Exception e) {}System.out.println(Thread.currentThread().getName() 完成售票余票为 (--ticket));}}finally {lock.unlock();//释放锁}}} }直接创建lock对象然后用lock()方法上锁最后用unlock()方法释放锁即可。 七、等待唤醒机制 1、虚假唤醒问题 生产消费模式是等待唤醒机制的一个经典案例看下面的代码 public class TestProductorAndconsumer {public static void main(String[] args){Clerk clerk new Clerk();Productor productor new Productor(clerk);Consumer consumer new Consumer(clerk);new Thread(productor,生产者A).start();new Thread(consumer,消费者B).start();} } //店员 class Clerk{private int product 0;//共享数据public synchronized void get(){ //进货if(product 10){System.out.println(产品已满);}else {System.out.println(Thread.currentThread().getName(): (product));}}public synchronized void sell(){//卖货if (product 0){System.out.println(缺货);}else {System.out.println(Thread.currentThread().getName(): (--product));}} } //生产者 class Productor implements Runnable{private Clerk clerk;public Productor(Clerk clerk){this.clerk clerk;}Overridepublic void run() {for (int i 0;i20;i){clerk.get();}} } //消费者 class Consumer implements Runnable{private Clerk clerk;public Consumer(Clerk clerk){this.clerk clerk;}Overridepublic void run() {for (int i 0;i20;i){clerk.sell();}} }这就是生产消费模式的案例这里没有使用等待唤醒机制运行结果就是即使是缺货状态它也会不断的去消费也会一直打印“缺货”即使是产品已满状态也会不断地进货。用等待唤醒机制改进 //店员 class Clerk{private int product 0;//共享数据public synchronized void get(){ //进货if(product 10){System.out.println(产品已满);try {this.wait();//满了就等待} catch (InterruptedException e) {e.printStackTrace();}}else {System.out.println(Thread.currentThread().getName(): (product));this.notifyAll();//没满就可以进货}}public synchronized void sell(){//卖货if (product 0){System.out.println(缺货);try {this.wait();//缺货就等待} catch (InterruptedException e) {e.printStackTrace();}}else {System.out.println(Thread.currentThread().getName(): (--product));this.notifyAll();//不缺货就可以卖}} }这样就不会出现上述问题了。没有的时候就生产生产满了就通知消费消费完了再通知生产。但是这样还是有点问题将上述代码做如下改动 if(product 1){ //把原来的10改成1System.out.println(产品已满);...... public void run() {try {Thread.sleep(200);//睡0.2秒} catch (InterruptedException e) {e.printStackTrace();}for (int i 0;i20;i){clerk.sell();} }就做这两处修改再次运行发现虽然结果没问题但是程序却一直没停下来。出现这种情况是因为有一个线程在等待而另一个线程没有执行机会了唤醒不了这个等待的线程了所以程序就无法结束。解决办法就是把get和sell方法里面的else去掉不要用else包起来。但是即使这样如果再多加两个线程就会出现负数了。 new Thread(productor, 生产者C).start(); new Thread(consumer, 消费者D).start();运行结果 一个消费者线程抢到执行权发现product是0就等待这个时候另一个消费者又抢到了执行权product是0还是等待此时两个消费者线程在同一处等待。然后当生产者生产了一个product后就会唤醒两个消费者发现product是1同时消费结果就出现了0和-1。这就是虚假唤醒。解决办法就是把if判断改成while。如下 public synchronized void get() { //进货while (product 1) {System.out.println(产品已满);try {this.wait();//满了就等待} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(Thread.currentThread().getName() : (product));this.notifyAll();//没满就可以进货}public synchronized void sell() {//卖货while (product 0) {//为了避免虚假唤醒问题wait方法应该总是在循环中使用System.out.println(缺货);try {this.wait();//缺货就等待} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(Thread.currentThread().getName() : (--product));this.notifyAll();//不缺货就可以卖}只需要把if改成while每次都再去判断一下就可以了。 2、用Lock锁实现等待唤醒 class Clerk {private int product 0;//共享数据private Lock lock new ReentrantLock();//创建锁对象private Condition condition lock.newCondition();//获取condition实例public void get() { //进货lock.lock();//上锁try {while (product 1) {System.out.println(产品已满);try {condition.await();//满了就等待} catch (InterruptedException e) {}}System.out.println(Thread.currentThread().getName() : (product));condition.signalAll();//没满就可以进货}finally {lock.unlock();//释放锁}}public void sell() {//卖货lock.lock();//上锁try {while (product 0) {System.out.println(缺货);try {condition.await();//缺货就等待} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(Thread.currentThread().getName() : (--product));condition.signalAll();//不缺货就可以卖}finally {lock.unlock();//释放锁}} }使用lock同步锁就不需要sychronized关键字了需要创建lock对象和condition实例。condition的await()方法、signal()方法和signalAll()方法分别与wait()方法、notify()方法和notifyAll()方法对应。 3、线程按序交替 首先来看一道题 编写一个程序开启 3 个线程这三个线程的 ID 分别为 A、B、C 每个线程将自己的 ID 在屏幕上打印 10 遍要求输出的结果必须按顺序显示。 如ABCABCABC…… 依次递归分析 线程本来是抢占式进行的要按序交替所以必须实现线程通信 那就要用到等待唤醒。可以使用同步方法也可以用同步锁。编码实现 public class TestLoopPrint {public static void main(String[] args) {AlternationDemo ad new AlternationDemo();new Thread(new Runnable() {Overridepublic void run() {for (int i 0; i 10; i) {ad.loopA();}}}, A).start();new Thread(new Runnable() {Overridepublic void run() {for (int i 0; i 10; i) {ad.loopB();}}}, B).start();new Thread(new Runnable() {Overridepublic void run() {for (int i 0; i 10; i) {ad.loopC();}}}, C).start();} }class AlternationDemo {private int number 1;//当前正在执行的线程的标记private Lock lock new ReentrantLock();Condition condition1 lock.newCondition();Condition condition2 lock.newCondition();Condition condition3 lock.newCondition();public void loopA() {lock.lock();try {if (number ! 1) { //判断condition1.await();}System.out.println(Thread.currentThread().getName());//打印number 2;condition2.signal();} catch (Exception e) {} finally {lock.unlock();}}public void loopB() {lock.lock();try {if (number ! 2) { //判断condition2.await();}System.out.println(Thread.currentThread().getName());//打印number 3;condition3.signal();} catch (Exception e) {} finally {lock.unlock();}}public void loopC() {lock.lock();try {if (number ! 3) { //判断condition3.await();}System.out.println(Thread.currentThread().getName());//打印number 1;condition1.signal();} catch (Exception e) {} finally {lock.unlock();}} }以上编码就满足需求。创建三个线程分别调用loopA、loopB和loopC方法这三个线程使用condition进行通信。 八、ReadWriterLock读写锁 我们在读数据的时候可以多个线程同时读不会出现问题但是写数据的时候如果多个线程同时写数据那么到底是写入哪个线程的数据呢所以如果有两个线程写写/读写需要互斥读读不需要互斥。这个时候可以用读写锁。看例子 public class TestReadWriterLock {public static void main(String[] args){ReadWriterLockDemo rw new ReadWriterLockDemo();new Thread(new Runnable() {//一个线程写Overridepublic void run() {rw.set((int)Math.random()*101);}},write:).start();for (int i 0;i100;i){//100个线程读Runnable runnable () - rw.get();Thread thread new Thread(runnable);thread.start();}} }class ReadWriterLockDemo{private int number 0;private ReadWriteLock readWriteLock new ReentrantReadWriteLock();//读(可以多个线程同时操作)public void get(){readWriteLock.readLock().lock();//上锁try {System.out.println(Thread.currentThread().getName():number);}finally {readWriteLock.readLock().unlock();//释放锁}}//写(一次只能有一个线程操作)public void set(int number){readWriteLock.writeLock().lock();try {System.out.println(Thread.currentThread().getName());this.number number;}finally {readWriteLock.writeLock().unlock();}} }这个就是读写锁的用法。上面的代码实现了一个线程写一百个线程同时读的操作。 九、线程池 我们使用线程时需要new一个用完了又要销毁这样频繁的创建销毁也很耗资源所以就提供了线程池。道理和连接池差不多连接池是为了避免频繁的创建和释放连接所以在连接池中就有一定数量的连接要用时从连接池拿出用完归还给连接池。线程池也一样。线程池中有一个线程队列里面保存着所有等待状态的线程。下面来看一下用法 public class TestThreadPool {public static void main(String[] args) {ThreadPoolDemo tp new ThreadPoolDemo();//1.创建线程池ExecutorService pool Executors.newFixedThreadPool(5);//2.为线程池中的线程分配任务pool.submit(tp);//3.关闭线程池pool.shutdown();} }class ThreadPoolDemo implements Runnable {private int i 0;Overridepublic void run() {while (i 100) {System.out.println(Thread.currentThread().getName() : (i));}} }线程池用法很简单分为三步。首先用工具类Executors创建线程池然后给线程池分配任务最后关闭线程池就行了。 总结 以上为本文全部内容涉及到了JUC的大部分内容。 本人也是初次接触如有错误希望大佬指点一二
http://wiki.neutronadmin.com/news/141823/

相关文章:

  • 申请一个网站得多钱联想企业网站建设的思路
  • 买源码做网站简单嘛wordpress页面缓存
  • 营业执照年报官网入口萌新seo
  • 网站内容好网站开发猪八戒
  • 做网站如何选择颜色阿里巴巴网站备案
  • 千鸟云网站建设怎么做一淘宝客网站吗
  • 泗县住房和城乡建设局网站上海网站建设shwzzz
  • joomla 网站图标网站配色模板
  • 网站免备案如何设公司产品购物网站
  • 建大型网站公司简介企业网络管理系统
  • 个人网站是啥电子商务网站中最基本的系统是
  • 免费推广网站大全下载网站app 开发
  • 网站设置访问密码网站首页的动态效果图怎么做
  • 专业找工作网站下载网站选项卡
  • 手机网站左右滑动平台开发是做什么的
  • 做任务给佣金的网站小程序平台商城
  • 东莞市网站seo内容优化吉利汽车网站开发环境分析
  • 做电商运营还是网站运营哪个好wordpress配置数据库失败6
  • 凡科建站网址红色经典ppt模板免费下载
  • 廊坊seo网站管理网站备案是域名还是空间
  • 加强政务公开与网站建设百度上做推广怎么做
  • 门户网站建设对策及建议网站开发培训课程表
  • 做网站切图网页转向网站
  • 网站联盟平台在线代理网页服务器
  • 网站建设对公司有什么好处邢台市最新人事调整
  • 做注册任务的网站有哪些四川建设行业数据共享平台网站问题
  • 无忧建站营销型网站概念
  • 网站开发确认函推广网页模板
  • 公众号做电影采集网站会被封做建材的网站有哪些
  • 网站左侧悬浮导航wordpress 权限修改