java多线程与并发--double_happy

CAS

结合 高并发 文章看!!!! 要不然看不懂

compare and swap. :
	比较 和 交换    
	在多线程 没有锁的 情况下 可以保证 多线程对一个 共享变量的 更新


使用:
	拿到内存中的最新值,使用CAS尝试将内存的值修改成目标值 如果修改失败,
	则获取内存位置的最新值,然后重新尝试,直到修改成功

注意:
	当前值,内存中最新值,目标值

 当前值 与 内存中最新值 进行比较 相等 就更新 目标值    不相等 说明 其他线程修改了这个共享变量的值  则然后重新尝试读取 当前值 与内存中最新值进行比较,直到修改成功 



CAS  缺点:
	开销大  一直do while
  它是可以保证原子性的
  
底层代码
 public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
            var5 = this.getIntVolatile(var1, var2);
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

        return var5;
    }

开销大 那么怎么办呢?  

ABA的问题 :
	表示  原始共享变量是 0   
	1号线程 读取的时候是 0     这个时候
	2号线程  读取0  修改成 2 
	3号线程 读取 2 修改成 0
	这个时候 1号线程 读取的 0  实际上  是 变了样的 0 

这就是 aba 问题  。  

就好比:
	你女朋友 分手之后 找了一个男的 之后 又跟你 复合了
所以 中间发生了什么 你要感知到 才行 。


解决ABA问题:
	共享变量 再 添加一个 版本号  即可    
	就是 读取共享变量的时候  不仅读取值 也要 读取版本号 

那么 CAS 的底层实现是什么呢???
	cas 和 sychroned 和 volatile 的底层实现 都一样

JUC

我们使用 多线程的目的 :
	就是提高效率 
	就是 尽可能的 利用 cpu资源   尽可能的利用系统资源 

如果 多线程使用 不合理 那么 可能导致性能 还不如 单线程 导致性能 更低


因为 多线程消耗的资源更多  涉及到 线程之间的调度 cpu 上下文之间的 切换 
以及 线程的 创建及销毁    还有同步  都是多线程的问题。	
jdk 1.5 之前 :
	sychornizde  和 volitail 
	就提供这两个 用于多线程的

1.5之后  jdk 提供了  java.util.current 包 这里面提供了 大量 线程相关的 工具类
那么 多线程 就是 你 
	如何利用更多的资源 做更多的事情

volatile 关键字

1.可见性
2. 有序性

它是不保证 原子性的
package com.juc;

public class VolatileAPP {

    public static void main(String[] args) {

        /**
         *
         */

        Data data = new Data();

        new Thread(()->{

            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            data.flag = true;

            System.out.println("flag = " +data.isFlag());

        }).start();

        
        while(true){
            if(data.isFlag()){
                System.out.println("-------------");
                break;
            }
        }



    }
}


class  Data {

    boolean flag = false;

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }
}
你可以使用 Data implements  Runnable  来实现 线程里面的 run方法 

我个人是不习惯  还是喜欢使用 lamda表达式的方式  因为我 scala 用的比 java熟悉 

上面的代码:
	两个线程:
		Thread  用来 修改 flag值
		main 用来 反复while ture 去读取flag值

那么 上面的 -----会被打印出来吗??
以及 while true 能不能结束?

在这里插入图片描述

结果:
	说明  两个线程之间 共享数据 是不可见的 

因为 thread 线程 以及 把 flag 修改成 true 
而 main 线程 读取的 flag  却是 flag

说明是有问题的:
	说明 两个线程之间 共享数据操作 是不可见的 
解决:
	1. synchronized 
	      这个关键字 你加在哪???看高并发的文章!!
	      	1.加在 isFlag方法那块 
	      	2.或者 你加在 while true 里面的if 都可以
	2. volatile     
class  Data {

    boolean flag = false;

    public synchronized boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }
}


我修改的是 这 
synchronized  效率极低 :
	  加锁这种效率是最低的  
	  如果多个线程 来 访问isFlag 方法 那么 需要判断 会发生阻塞! 效率很低


使用 volatile :
	他就是 多线程情况下操作 共享数据 是可以保证 共享数据的可见性

即:
class  Data {

    volatile boolean flag = false;

    public  boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }
}


但是 volatile 是不能保证 原子性的!

原子性:
	你可以理解为  :
		一次操作 要么成功 要么失败    所以你一晚上 几次??

原子性

i++ 的原子性问题!:
	很好的一个案例

结合cpu cache : 你可以知道
	i++ 操作 实际上是 三步:
		1.从主存 读取 i   放到 cpu cache里
		2. 线程 读取 cpu cache值 进行修改
		3.  修改后的 cpu cache值 写回 主存
	读 --》修改---》写回

这三步 每一步都是具有原子性的  但是 
三步结合在一起 是不具有原子性的!!!
package com.juc;

public class AtomicApp {

    public static void main(String[] args)  {


        AtomicData atomicData = new AtomicData();

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

            new Thread(()->{

                for (int j = 0; j <1000 ; j++) {
                    atomicData.increate();
                }

            },"AtomicApp"+i).start();

        }

        while (Thread.activeCount() > 2) {  //>2 因为一个 main 一个gc
            Thread.yield();
        }
        
        System.out.println(Thread.currentThread().getName()+",number is : " +atomicData.number);


        //单线程 
//        for (int j = 0; j <1000 ; j++) {
//            atomicData.increate();
//        }
//
//        System.out.println(Thread.currentThread().getName()+",number is : " +atomicData.number);




    }
}

class  AtomicData {

    int number = 0;

    public int increate(){
        return number++;
    }

}
结果:
	单线程下 结果是 1000  是没有问题的 
	多线程情况下 正常结果应该是 20000 但是 不是!!

这就说明  number++; 操作 是不具有原子性  在多线程下 是用问题的!!!


但是真正的理解是:
	number ++  是三步操作  
		多线程下 你会觉得是 可见性导致的  但是 不准确  因为 原子性!!
		如果是可见性 你加一个volatile 即可 但是 number++ 三步在一起 是不具有原子性的 
		volatile 是不能解决 原子性的 

要想解决:
	1。原子变量  
		jdk1.5之后提供的  java.util.concurrent.atomic包下 
	2.sychronized  
package com.juc;

import java.util.concurrent.atomic.AtomicInteger;

public class AtomicApp {

    public static void main(String[] args)  {


        AtomicData atomicData = new AtomicData();

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

            new Thread(()->{

                for (int j = 0; j <1000 ; j++) {
                    atomicData.increase2();
                }

            },"AtomicApp"+i).start();

        }

        while (Thread.activeCount() > 2) {  //>2 因为一个 main 一个gc
            Thread.yield();
        }


        System.out.println(Thread.currentThread().getName()+",number is : " +atomicData.number);
        System.out.println(Thread.currentThread().getName()+",number is : " +atomicData.atomicInteger);


        //单线程
//        for (int j = 0; j <1000 ; j++) {
//            atomicData.increate();
//        }
//
//        System.out.println(Thread.currentThread().getName()+",number is : " +atomicData.number);




    }
}

class  AtomicData {

    int number = 0;

//第一种解决
    public synchronized int increate(){
        return number++;
    }

//第二种解决
    AtomicInteger atomicInteger = new AtomicInteger();
    public  void increase2(){
        atomicInteger.getAndIncrement();
    }

}
文章开始提到:
	CAS算法是可以解决 原子性问题

那么原子类 就是调用 CAS算法!!  文章最开始就是源码
原子变量:
	以AtomicInteger 为例 看源码

AtomicInteger源码:

public class AtomicInteger extends Number implements java.io.Serializable {

  private volatile int value;
  
	public final int getAndIncrement() {
        return unsafe.getAndAddInt(this, valueOffset, 1);
    }
}

getAndIncrement 实现:

 public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
            var5 = this.getIntVolatile(var1, var2);
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

        return var5;
    }

compareAndSwapInt 实现的就是 cas算法

结论:原子变量
1. volatile int value;  保证值 的 可见性
2. CAS算法保证 数据的原子性


CAS:
	当前值,内存中最新值,目标值
	可以理解为:
		内存值V
		内存中最新值A
		更新值B
		当且仅当 V==A ,把 B的值 赋值给 V   即 多线程情况下 只有一个线程会成功

cas效率高 是因为 它不会阻塞  但是如果要自己实现cas的  需要对 为修改成功后的步骤该
如何做 要自己实现  类似原子类里面的这个方法!!

下图 就是cas 过程

在这里插入图片描述
模拟CAS算法

package com.juc;

public class CASAPPComplement {

    public static void main(String[] args) {


        CompareAndSwap cas = new CompareAndSwap();

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

            new Thread(()->{

                int expectValue = cas.get();

                boolean sucess = cas.compareAndSet(expectValue, (int) (Math.random() * 101));

                System.out.println("是否成功:"+sucess);

            }).start();

        }

    }
}

class CompareAndSwap{

    int value;

    //获取内存值
    public synchronized int get(){
        return value;
    }

    //比较
    public synchronized int compareAndSwap(int expectValue, int newValue) {

        int oldValue = value;

        if (oldValue == expectValue) {
            this.value = newValue;
        }

        return oldValue;
    }

    //设置值
    public synchronized boolean compareAndSet(int expectValue, int newValue){
        return expectValue == compareAndSwap(expectValue, newValue);
    }
}
底层  绝对不是用 synchronized 这个的哈

ConcurrentHashMap 锁分段机制

是一个线程安全的 HashMap    

它是jdk1.5 之后那个包 里面提供的

那么HashMap 和HashTable 有什么区别??

HashMap 是线程不安全的 
HashTable 是线程安全的     效率低!锁表  实际上就是 并行转换成 串行的一个操作!!

如果HashTable 遇到 复合操作 就是线程不安全的!:
	eg:
		若不存在就添加
if(!table.contants()){
 table.put
}

contants 和put 方法各自具有 独立的锁  但是 和在一起 就不具有独立的锁  有线程问题!!

ConcurrentHashMap:锁分段机制

	concurrentLevel  : 分段级别 默认的级别是16
	也就是ConcurrentHashMap 里面有16 段 每一段 叫 segment
	每个 segment 有独立的表 
	好处就是 :
		每个 segment 都有一个独立的锁
   那么 多线程情况下 就可以并发访问不同的 segment  效率高

1.8 之后 每隔segment 采用的是 cas  1.5采用的是 锁



注意:
  ConcurrentHashMap   -》HashMap
  ConcurrentSkipListMap -》TreeMap
  CopyOnWriteArrayList -》 ArrayList
  CopyOnWriteArraySet  -> ArrayAet

这些多线程容器都优于 jdk原生的	
那么他们都解决什么问题呢??

package com.juc;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

/**
 * 写入 并复制
 */
public class CopyOnWriteArrayListApp {
    public static void main(String[] args) {

        ListTest listTest = new ListTest();

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

            new Thread(()->{

                Iterator<String>  it = listTest.list.iterator();

                //边取 边加
                while (it.hasNext()) {
                    System.out.println(it.next());

                    listTest.list.add("AA");
                }

            }).start();

        }



    }
}

class  ListTest{

    static  List<String> list =  Collections.synchronizedList(new ArrayList<String>());

   static {
       list.add("AA");
       list.add("BB");
       list.add("CC");
   }


}
结果:
	发生  并发修改 异常
java.util.ConcurrentModificationException
	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
	at java.util.ArrayList$Itr.next(ArrayList.java:859)
	at com.juc.CopyOnWriteArrayListApp.lambda$main$0(CopyOnWriteArrayListApp.java:24)
	at java.lang.Thread.run(Thread.java:748)


因为 读取 和添加 操作的 是 同一个数据源 就会发生 并发修改异常! 你一个线程跑 也是这个问题 

也就是:
	不能  读取 和添加 操作的 是 同一个数据源

使用 CopyOnWriteArrayList  可以解决
class  ListTest{

//    static  List<String> list =  Collections.synchronizedList(new ArrayList<String>());
    
    static  CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();

   static {
       list.add("AA");
       list.add("BB");
       list.add("CC");
   }
}


注意:
但是 添加操作 不适合它 因为是写入并复制  复制!!

并发的迭代 操作 它的效率很高!!

CountDownLatch 闭锁

也就是 
	当你要完成一些运算 这些运算没有完成 那就等待这些运算完成
	我在继续执行!!
package com.juc;

import java.util.concurrent.CountDownLatch;

public class CountDownLatchApp {
    public static void main(String[] args) {


        CountDownLatch latch = new CountDownLatch(10);

        long start = System.currentTimeMillis();

        //打印 5w 以内偶数
        for (int i = 0; i <10 ; i++) {

            new Thread(()->{

                for (int j = 0; j <50000 ; j++) {

                    if (j % 2 == 0) {
                        System.out.println(j);
                    }
                }
            }).start();

        }


        long end = System.currentTimeMillis();

        System.out.println("执行时间: " +(end -start));
        

    }
}


上面代码 想 计算:
	10个线程 做 5w以内的偶数打印 的执行时间 

是没有办法计算的 :
	因为:
		main 和 10个线程 是同时执行的   上面的代码 算得不准确   

  不能保证 10个线程 执行完了  再计算 执行时间 !!!!

所以有个执行的先后顺序的 !!!


解决这个问题:如下
	必须用到 闭锁!!
package com.juc;

import java.util.concurrent.CountDownLatch;

public class CountDownLatchApp {
    public static void main(String[] args) throws InterruptedException {


        CountDownLatch latch = new CountDownLatch(10);

        long start = System.currentTimeMillis();

        //打印 5w 以内偶数
        for (int i = 0; i <10 ; i++) {

            new Thread(()->{

                for (int j = 0; j <50000 ; j++) {

                    if (j % 2 == 0) {
                        System.out.println(j);
                    }
                }

                latch.countDown();
            }).start();

        }

        latch.await();

        long end = System.currentTimeMillis();

        System.out.println("执行时间: " +(end -start) +"ms");


    }
}

结果:

在这里插入图片描述

CountDownLatch latch = new CountDownLatch(10);



10 : 完成一个线程操作     就递减1    直到减到 0

main 线程 才执行 


所以:
	1. 10个线程里 要有  latch.countDown();  
	2. main   有一个 latch.await()


所以 闭锁这个操作 应用很广泛  很重要!!

Lock同步锁

用于 解决多线程安全的方式:
	1. 同步代码块      synchronized   可以称为隐式锁
	2. 同步方法       synchronized    可以称为隐式锁
	
	jdk1.5 之后  更灵活的方式!!!
	3. 同步锁
	   是一个显示锁 需要 通过lock() 方法上锁,
	   必须通过unlock() 方法进行释放锁

注意:
	必须通过unlock() 方法进行释放锁
如果不释放会有很多问题 最好放在 finally里面


而 synchronized 就不需要 它是 jvm 底层帮自己维护
package com.juc;

import java.util.concurrent.atomic.AtomicInteger;

public class LockApp {

    public static void main(String[] args) {

        Ticket ticket = new Ticket();

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

            new Thread(()->{

                while (true) {

                    if (ticket.getTicket() > 0) {
                        System.out.println(Thread.currentThread().getName()+" 完成售票,余票为:"+ --ticket.ticket);
//                        System.out.println(Thread.currentThread().getName()+" 完成售票,余票为:"+ ticket.a.decrementAndGet());
                    }

                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },i+"号窗口").start();
        }


    }
}

class Ticket{

    int ticket = 100;

//    AtomicInteger a = new AtomicInteger(100);


    public int getTicket() {
        return ticket;
    }

}
上面的一个经典案例:
	卖票!!

你可以使用 原子类来解决 

那么使用 Lock 该如何做呢??

package com.juc;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockApp {

    public static void main(String[] args) {

        Ticket ticket = new Ticket();

        Lock lock = new ReentrantLock();

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

            new Thread(() -> {

                //上锁
                lock.lock();

                try {
                    while (true) {

                        if (ticket.getTicket() > 0) {
                            System.out.println(Thread.currentThread().getName() + " 完成售票,余票为:" + --ticket.ticket);
                        }

                        try {
                            Thread.sleep(200);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }

                    }
                } finally {
                  //释放锁
                    lock.unlock();
                }


            }, i + "号窗口").start();
        }


    }
}

class Ticket {

    int ticket = 100;

    public int getTicket() {
        return ticket;
    }

}

等待唤醒机制

synchronized:
	它是 wait 和 notify 来完成 但是效率低 对吧!!

那么 如何使用 lock 同步锁 来实现   等待唤醒机制!!!呢??

package com.juc;

public class ProducerAndConsumerApp {
    public static void main(String[] args) {

        Clerk clerk = new Clerk();
        Producer producer = new Producer(clerk);
        Consumer consumer = new Consumer(clerk);
        
        
        
        new Thread(()->{

            //生产货物
            for (int i = 0; i <20 ; i++) {
                producer.clerk.get();
            }
            
        },"producer").start();
        
        new Thread(()->{
            
            //卖货
            for (int i = 0; i <20 ; i++) {
                consumer.clerk.sale();
            }
            
        },"consumer").start();
        
        

    }
}


//店员
class Clerk{
    
    int product = 0;
    
    //进货
    public synchronized void  get(){
        if (product >= 10) {
            System.out.println("产品已满!");
        }else {
            System.out.println(Thread.currentThread().getName()+" : " + ++product);
        }
    }
    
    //卖货
    public  synchronized void sale(){
        if (product <= 0) {
            System.out.println("缺货!");
        }else {
            System.out.println(Thread.currentThread().getName()+" : " + --product);
        }
    }
}

//producer
class Producer{
    
    Clerk clerk;

    public Producer(Clerk clerk) {
        this.clerk = clerk;
    }
    
}

class Consumer{

    Clerk clerk;

    public Consumer(Clerk clerk) {
        this.clerk = clerk;
    }

}

结果:
producer : 2
producer : 3
producer : 4
producer : 5
producer : 6
producer : 7
producer : 8
consumer : 7
consumer : 6
consumer : 5
consumer : 4
consumer : 3
consumer : 2
consumer : 1
consumer : 0
缺货!
缺货!
缺货!
缺货!
缺货!
缺货!
缺货!
缺货!
缺货!
缺货!
缺货!
缺货!
producer : 1
producer : 2
producer : 3
producer : 4
producer : 5
producer : 6
producer : 7
producer : 8
producer : 9
producer : 10
产品已满!
产品已满!
上面是 生产者和消费者案例 :
	1.没有采用 等待唤醒机制 会有什么问题

生产者 不断发送数据  消费值不断消费 !!
会造成 数据丢失问题!! 或者数据重复消费 问题!!
就看 谁生产快 和消费快了  这是有问题的!!

加入等待唤醒机制!
package com.juc;

public class ProducerAndConsumerApp {
    public static void main(String[] args) {

        Clerk clerk = new Clerk();
        Producer producer = new Producer(clerk);
        Consumer consumer = new Consumer(clerk);



        new Thread(()->{

            //生产货物
            for (int i = 0; i <20 ; i++) {
                producer.clerk.get();
            }

        },"producer").start();

        new Thread(()->{

            //卖货
            for (int i = 0; i <20 ; i++) {
                consumer.clerk.sale();
            }

        },"consumer").start();



    }
}


//店员
class Clerk{

    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 sale(){
        if (product <= 0) {
            System.out.println("缺货!");

            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }else {
            System.out.println(Thread.currentThread().getName()+" : " + --product);

            this.notifyAll();
        }
    }
}

//producer
class Producer{

    Clerk clerk;

    public Producer(Clerk clerk) {
        this.clerk = clerk;
    }

}

class Consumer{

    Clerk clerk;

    public Consumer(Clerk clerk) {
        this.clerk = clerk;
    }

}
结果:
producer : 1
producer : 2
producer : 3
producer : 4
producer : 5
producer : 6
producer : 7
producer : 8
producer : 9
producer : 10
产品已满!
consumer : 9
consumer : 8
consumer : 7
consumer : 6
consumer : 5
consumer : 4
consumer : 3
consumer : 2
consumer : 1
consumer : 0
缺货!
producer : 1
producer : 2
producer : 3
producer : 4
producer : 5
producer : 6
producer : 7
producer : 8
producer : 9
consumer : 8
consumer : 7
consumer : 6
consumer : 5
consumer : 4
consumer : 3
consumer : 2
consumer : 1
consumer : 0


只要发现:
	生产满了 就赶紧消费
	缺货 就赶紧生产

这样才是 有效的数据!!  
这种是效率低的问题吗???

改一下 :
	把生产者 生产货物 变成1
消费完 再 睡200ms

会造成 程序一只运行 不会结束!!
package com.juc;

public class ProducerAndConsumerApp {
    public static void main(String[] args) {

        Clerk clerk = new Clerk();
        Producer producer = new Producer(clerk);
        Consumer consumer = new Consumer(clerk);



        new Thread(()->{


            //生产货物
            for (int i = 0; i <20 ; i++) {
                producer.clerk.get();
            }

        },"producer").start();

        new Thread(()->{

            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            //卖货
            for (int i = 0; i <20 ; i++) {
                consumer.clerk.sale();
            }

        },"consumer").start();



    }
}


//店员
class Clerk{

    int product = 0;

    //进货
    public synchronized void  get(){
        if (product >= 1) {
            System.out.println("产品已满!");

            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }else {
            System.out.println(Thread.currentThread().getName()+" : " + ++product);

            this.notifyAll();
        }
    }

    //卖货
    public  synchronized void sale(){
        if (product <= 0) {
            System.out.println("缺货!");

            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }else {
            System.out.println(Thread.currentThread().getName()+" : " + --product);

            this.notifyAll();
        }
    }
}

//producer
class Producer{

    Clerk clerk;

    public Producer(Clerk clerk) {
        this.clerk = clerk;
    }

}

class Consumer{

    Clerk clerk;

    public Consumer(Clerk clerk) {
        this.clerk = clerk;
    }

}

在这里插入图片描述

问题发生在:
	sale 和 get方法 里面的 else那块 

因为:
	当product =0 
 public  synchronized void sale(){
        if (product <= 0) {
            System.out.println("缺货!");

            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }else {
            System.out.println(Thread.currentThread().getName()+" : " + --product);

            this.notifyAll();
        }
    }

代码运行在   this.wait(); 这
this.wait():	
	等在这个位置  同时释放锁的资源 
	当他被唤醒之后 从this.wait() 代码的位置 往下继续执行

那么此时 生产者线程:
public synchronized void  get(){
        if (product >= 1) {
            System.out.println("产品已满!");

            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }else {
            System.out.println(Thread.currentThread().getName()+" : " + ++product);

            this.notifyAll();
        }
    }

代码运行 else  ++product  导致product 变为1 
然后 this.notifyAll();  释放锁 之后 

此时 开始生产者和消费值继续抢占cpu  如果 消费者 抢到!!
 消费者会 接着从 sale 方法里面的  this.wait(); 往下执行 跳出else 就是消费者
  执行完毕ok了
 就剩下 生产者一个线程了 

接着 生产者 发现 product=1  会运行 
	System.out.println("产品已满!");
	this.wait();   释放锁等待被 唤醒 !!!  但是 没有消费者线程 了 
	所以不会被唤醒!!


所以代码会卡住在 : 程序结束不了!!!
	产品已满 或者 缺货
解决:
	把else 去掉
package com.juc;

public class ProducerAndConsumerApp {
    public static void main(String[] args) {

        Clerk clerk = new Clerk();
        Producer producer = new Producer(clerk);
        Consumer consumer = new Consumer(clerk);



        new Thread(()->{


            //生产货物
            for (int i = 0; i <20 ; i++) {
                producer.clerk.get();
            }

        },"producer").start();

        new Thread(()->{

            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            //卖货
            for (int i = 0; i <20 ; i++) {
                consumer.clerk.sale();
            }

        },"consumer").start();



    }
}


//店员
class Clerk{

    int product = 0;

    //进货
    public synchronized void  get(){
        if (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 sale(){
        if (product <= 0) {
            System.out.println("缺货!");

            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

            System.out.println(Thread.currentThread().getName()+" : " + --product);

            this.notifyAll();
    }
}

//producer
class Producer{

    Clerk clerk;

    public Producer(Clerk clerk) {
        this.clerk = clerk;
    }

}

class Consumer{

    Clerk clerk;

    public Consumer(Clerk clerk) {
        this.clerk = clerk;
    }

}


程序可以结束!!
还是有问题的!!:
	多个线程 就会有问题 
	上面是一个生产者一个消费值线程 是没有问题的 
	那么 两个消费者 两个生产者 就会有问题!!
package com.juc;

public class ProducerAndConsumerApp {
    public static void main(String[] args) {

        Clerk clerk = new Clerk();
        Producer producer = new Producer(clerk);
        Consumer consumer = new Consumer(clerk);


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

            new Thread(()->{


                //生产货物
                for (int i = 0; i <20 ; i++) {
                    producer.clerk.get();
                }

            },"producer"+j).start();

            new Thread(()->{

//                try {
////                    Thread.sleep(2000);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }

                //卖货
                for (int i = 0; i <20 ; i++) {
                    consumer.clerk.sale();
                }

            },"consumer"+j).start();
        }




    }
}


//店员
class Clerk{

    int product = 0;

    //进货
    public synchronized void  get(){
        if (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 sale(){
        if (product <= 0) {
            System.out.println("缺货!");

            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

            System.out.println(Thread.currentThread().getName()+" : " + --product);

            this.notifyAll();
    }
}

//producer
class Producer{

    Clerk clerk;

    public Producer(Clerk clerk) {
        this.clerk = clerk;
    }

}

class Consumer{

    Clerk clerk;

    public Consumer(Clerk clerk) {
        this.clerk = clerk;
    }

}
结果:

producer0 : 1
产品已满!
consumer0 : 0
缺货!
producer1 : 1
产品已满!
producer0 : 2
产品已满!
producer1 : 3
产品已满!
consumer0 : 2
consumer0 : 1
consumer0 : 0
缺货!
缺货!
producer1 : 1
产品已满!
producer0 : 2
产品已满!
producer1 : 3
产品已满!
consumer1 : 2
consumer1 : 1
consumer1 : 0
缺货!
consumer0 : -1
缺货!
consumer1 : -2
缺货!
producer1 : -1
producer1 : 0
producer1 : 1
产品已满!
producer0 : 2
产品已满!
producer1 : 3
产品已满!
consumer1 : 2
consumer1 : 1
consumer1 : 0
缺货!
consumer0 : -1
缺货!
consumer1 : -2
缺货!
producer1 : -1
producer1 : 0
producer1 : 1
产品已满!
producer0 : 2
产品已满!
producer1 : 3
产品已满!
consumer1 : 2
consumer1 : 1
consumer1 : 0
缺货!
consumer0 : -1
缺货!
consumer1 : -2
缺货!
producer1 : -1
producer1 : 0
producer1 : 1
产品已满!
producer0 : 2
产品已满!



都出现负数了!!

如何导致的:
	public  synchronized void sale(){
        if (product <= 0) {
            System.out.println("缺货!");

            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

            System.out.println(Thread.currentThread().getName()+" : " + --product);

            this.notifyAll();
    }

两个线程 都进到这个方法 :
	都停在 this.wait();   如果 同时被 唤醒 
	product=0   --product之后 就出现负数了

这就是虚假唤醒问题!!!
官网的解释是 :
	this.wait(); 必须使用在 while  
	所以要把 if 变成 while  为什么呢??
	就是 要再判断一次!!! 就解决了!虚假唤醒问题!
	
package com.juc;

public class ProducerAndConsumerApp {
    public static void main(String[] args) {

        Clerk clerk = new Clerk();
        Producer producer = new Producer(clerk);
        Consumer consumer = new Consumer(clerk);


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

            new Thread(()->{


                //生产货物
                for (int i = 0; i <20 ; i++) {
                    producer.clerk.get();
                }

            },"producer"+j).start();

            new Thread(()->{

//                try {
////                    Thread.sleep(2000);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }

                //卖货
                for (int i = 0; i <20 ; i++) {
                    consumer.clerk.sale();
                }

            },"consumer"+j).start();
        }




    }
}


//店员
class Clerk{

    int product = 0;

    //进货
    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 sale(){
        while (product <= 0) {
            System.out.println("缺货!");

            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

            System.out.println(Thread.currentThread().getName()+" : " + --product);

            this.notifyAll();
    }
}

//producer
class Producer{

    Clerk clerk;

    public Producer(Clerk clerk) {
        this.clerk = clerk;
    }

}

class Consumer{

    Clerk clerk;

    public Consumer(Clerk clerk) {
        this.clerk = clerk;
    }

}
那么 以上是 使用 synchronized 和 wait + notify的方式 完成等待唤醒机制

如何使用lock完成等待唤醒机制呢???

lock 完成等待唤醒机制

wait 和 notify  
Lock 有自己的 
	叫 Condition  控制线程通信
		await、signal、signalAll

Condition 是通过特定的Lock获取  newCondition

就可以使用等待唤醒机制了!!!
package com.juc;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ProducerAndConsumerLockApp {
    public static void main(String[] args) {

        Clerk01 clerk = new Clerk01();
        Producer01 producer = new Producer01(clerk);
        Consumer01 consumer = new Consumer01(clerk);


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

            new Thread(()->{

                //生产货物
                for (int i = 0; i <20 ; i++) {
                    producer.clerk.get();
                }

            },"producer"+j).start();

            new Thread(()->{

                //卖货
                for (int i = 0; i <20 ; i++) {
                    consumer.clerk.sale();
                }

            },"consumer"+j).start();
        }




    }
}


//店员
class Clerk01 {

    int product = 0;


    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    //进货
    public  void  get(){

        lock.lock();

       try{
           while (product >= 1) {
               System.out.println("产品已满!");

               try {
                   condition.await();
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }

           }
           System.out.println(Thread.currentThread().getName()+" : " + ++product);

           condition.signalAll();
       }finally {
           lock.unlock();
       }
    }

    //卖货
    public   void sale(){

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

//producer
class Producer01 {

    Clerk01 clerk;

    public Producer01(Clerk01 clerk) {
        this.clerk = clerk;
    }

}

class Consumer01 {

    Clerk01 clerk;

    public Consumer01(Clerk01 clerk) {
        this.clerk = clerk;
    }

}

线程按序交替

eg:
	编写一个程序,开启3个线程,这三个线程的ID分别是A、B、C、每个线程
	将自己的ID在屏幕上打印10遍,要求输出的结果必须按顺序显示。
		如:
			ABCABCABC。。。ABC依次递归
分析:
	1.对线程控制 需要 Lock
	2.对线程 按顺序控制 就需要 Condition
package com.juc;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ABCAPP {

    public static void main(String[] args) {

        ABC abc = new ABC();

        new Thread(()->{

            for (int i = 0; i < 10; i++) {
                abc.printA(i);
            }

        },"A").start();

        new Thread(()->{

            for (int i = 0; i < 10; i++) {
                abc.printB(i);
            }

        },"B").start();

        new Thread(()->{

            for (int i = 0; i < 10; i++) {
                abc.printC(i);

                System.out.println("---------------------------");
            }

        },"C").start();

    }
}

class ABC{

    //当前正在执行线程的标记
    int number =1;

   Lock lock  = new ReentrantLock();
   Condition condition1 = lock.newCondition();
   Condition condition2 = lock.newCondition();
   Condition condition3 = lock.newCondition();

    /**
     *
     * @param totalprint  表示循环几轮
     * @throws InterruptedException
     */
   public void printA(int totalprint)  {
       lock.lock();

       try{

           //1.判断
           if(number !=1){

               condition1.await();
           }

           //2.打印
           for (int i = 0; i <10 ; i++) {
               System.out.println(Thread.currentThread().getName()+"\t" +i+"\t" +totalprint);
           }

           //3.唤醒
           number =2;
           condition2.signal();

       } catch (InterruptedException e) {
           e.printStackTrace();
       } finally {
           lock.unlock();
       }

   }


    public void printB(int totalprint)  {
        lock.lock();

        try{

            //1.判断
            if(number !=2){
                condition2.await();
            }

            //2.打印
            for (int i = 0; i <10 ; i++) {
                System.out.println(Thread.currentThread().getName()+"\t" +i+"\t" +totalprint);
            }

            //3.唤醒
            number =3;
            condition3.signal();

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }


    public void printC(int totalprint)  {
        lock.lock();

        try{

            //1.判断
            if(number !=3){
                condition3.await();
            }

            //2.打印
            for (int i = 0; i <10 ; i++) {
                System.out.println(Thread.currentThread().getName()+"\t" +i+"\t" +totalprint);
            }

            //3.唤醒
            number =1;
            condition1.signal();

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }


}
上面的代码 :
	是 10轮 打印10次

结果:
A	0	0
A	1	0
A	2	0
A	3	0
A	4	0
A	5	0
A	6	0
A	7	0
A	8	0
A	9	0
B	0	0
B	1	0
B	2	0
B	3	0
B	4	0
B	5	0
B	6	0
B	7	0
B	8	0
B	9	0
C	0	0
C	1	0
C	2	0
C	3	0
C	4	0
C	5	0
C	6	0
C	7	0
C	8	0
C	9	0
---------------------------
A	0	1
A	1	1
A	2	1
A	3	1
A	4	1
A	5	1
A	6	1
A	7	1
A	8	1
A	9	1
B	0	1
B	1	1
B	2	1
B	3	1
B	4	1
B	5	1
B	6	1
B	7	1
B	8	1
B	9	1
C	0	1
C	1	1
C	2	1
C	3	1
C	4	1
C	5	1
C	6	1
C	7	1
C	8	1
C	9	1
---------------------------
A	0	2
A	1	2
A	2	2
A	3	2
A	4	2
A	5	2
A	6	2
A	7	2
A	8	2
A	9	2
B	0	2
B	1	2
B	2	2
B	3	2
B	4	2
B	5	2
B	6	2
B	7	2
B	8	2
B	9	2
C	0	2
C	1	2
C	2	2
C	3	2
C	4	2
C	5	2
C	6	2
C	7	2
C	8	2
C	9	2
---------------------------

ReadWriteLock读写锁

就是读写分离:

什么情况下使用呢?
	1.写 多线程   就是 写写 要互斥
	2.读写   读和写 也要互斥
	3.读读 是不需要互斥的  
package com.juc;

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteApp {

    public static void main(String[] args) {

        /**
         * 那么一个线程去 写 100 个线程去读
         */
        Demo demo = new Demo();

        new Thread(()->{
            demo.set((int)(Math.random()*101));
        },"write").start();


        for (int i = 0; i < 100; i++) {
            new Thread(()->{
                demo.get();
            },"read").start();
        }


    }
}


class Demo{

    int number = 0;
    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();
        }

    }


}
结果:
write
read : 36
read : 36
read : 36
read : 36
read : 36
read : 36
。。。

一个线程再 写 100个线程再 读  这就是 读写锁

线程八锁

1.1.两个普通同步方法 两个线程 标准打印 ,  //one two
package com.juc;

/**
 * 判断 打印的是 one 还是 two
 * 
 * 1.两个普通同步方法 两个线程 标准打印 ,  //one two
 * 
 */
public class Thread8Monitor {

    public static void main(String[] args) {

        Number number = new Number();


            new Thread(()->{
                number.getOne();
            }).start();

            new Thread(()->{

                number.getTwo();
            }).start();
    }
}

class  Number{

    public synchronized void getOne(){
        System.out.println("one");
    }

    public synchronized void getTwo(){
        System.out.println("two");
    }
}
结果:
one
two
2. 新增 Thread.sleep 给 getone方法   
package com.juc;

/**
 * 判断 打印的是 one 还是 two
 *
 * 1.两个普通同步方法 两个线程 标准打印 ,  //one two
 *
 */
public class Thread8Monitor {

    public static void main(String[] args) {

        Number number = new Number();


            new Thread(()->{
                number.getOne();
            }).start();

            new Thread(()->{

                number.getTwo();
            }).start();
    }
}

class  Number{

    public synchronized void getOne(){
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("one");
    }

    public synchronized void getTwo(){
        System.out.println("two");
    }
}



结果:
one
two

3.新增 getThree 普通方法 

package com.juc;

/**
 * 判断 打印的是 one 还是 two
 *
 * 1.两个普通同步方法 两个线程 标准打印 ,  //one two
 *
 */
public class Thread8Monitor {

    public static void main(String[] args) {

        Number number = new Number();


            new Thread(()->{
                number.getOne();
            }).start();

            new Thread(()->{

                number.getTwo();
            }).start();

        new Thread(()->{

            number.getThree();
        }).start();
    }
}

class  Number{

    public synchronized void getOne(){
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("one");
    }

    public synchronized void getTwo(){
        System.out.println("two");
    }

    public void getThree(){
        System.out.println("three");
    }
}

结果:
three
one
two
4.两个普通同步方法 两个Number对象  打印?

package com.juc;

/**
 * 判断 打印的是 one 还是 two
 *
 * 1.两个普通同步方法 两个线程 标准打印 ,  //one two
 *
 */
public class Thread8Monitor {

    public static void main(String[] args) {

        Number number = new Number();
        Number number2 = new Number();


            new Thread(()->{
                number.getOne();
            }).start();

            new Thread(()->{

                number2.getTwo();
            }).start();

//        new Thread(()->{
//
//            number.getThree();
//        }).start();
    }
}

class  Number{

    public synchronized void getOne(){
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("one");
    }

    public synchronized void getTwo(){
        System.out.println("two");
    }

//    public void getThree(){
//        System.out.println("three");
//    }
}

结果:
two
one
5.修改 getOne为 静态的同步方法 打印? two one

package com.juc;

/**
 * 判断 打印的是 one 还是 two
 *
 * 1.两个普通同步方法 两个线程 标准打印 ,  //one two
 *
 */
public class Thread8Monitor {

    public static void main(String[] args) {

        Number number = new Number();
//        Number number2 = new Number();


            new Thread(()->{
                number.getOne();
            }).start();

            new Thread(()->{

                number.getTwo();
            }).start();

//        new Thread(()->{
//
//            number.getThree();
//        }).start();
    }
}

class  Number{

    public static synchronized void getOne(){
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("one");
    }

    public synchronized void getTwo(){
        System.out.println("two");
    }

//    public void getThree(){
//        System.out.println("three");
//    }
}


结果:
two
one
6. 修改两个同步方法都为静态方法 

package com.juc;

/**
 * 判断 打印的是 one 还是 two
 *
 * 1.两个普通同步方法 两个线程 标准打印 ,  //one two
 *
 */
public class Thread8Monitor {

    public static void main(String[] args) {

        Number number = new Number();
//        Number number2 = new Number();


            new Thread(()->{
                number.getOne();
            }).start();

            new Thread(()->{

                number.getTwo();
            }).start();

//        new Thread(()->{
//
//            number.getThree();
//        }).start();
    }
}

class  Number{

    public static synchronized void getOne(){
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("one");
    }

    public static synchronized void getTwo(){
        System.out.println("two");
    }

//    public void getThree(){
//        System.out.println("three");
//    }
}

结果:
one
two
7.  一个静态同步方法 一个非静态同步方法 两个Number对象
package com.juc;

/**
 * 判断 打印的是 one 还是 two
 *
 * 1.两个普通同步方法 两个线程 标准打印 ,  //one two
 *
 */
public class Thread8Monitor {

    public static void main(String[] args) {

        Number number = new Number();
        Number number2 = new Number();


            new Thread(()->{
                number.getOne();
            }).start();

            new Thread(()->{

                number2.getTwo();
            }).start();

//        new Thread(()->{
//
//            number.getThree();
//        }).start();
    }
}

class  Number{

    public static synchronized void getOne(){
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("one");
    }

    public  synchronized void getTwo(){
        System.out.println("two");
    }

//    public void getThree(){
//        System.out.println("three");
//    }
}

结果:
two
one
8.两个静态同步方法  两个Number对象
package com.juc;

/**
 * 判断 打印的是 one 还是 two
 *
 * 1.两个普通同步方法 两个线程 标准打印 ,  //one two
 *
 */
public class Thread8Monitor {

    public static void main(String[] args) {

        Number number = new Number();
        Number number2 = new Number();


            new Thread(()->{
                number.getOne();
            }).start();

            new Thread(()->{

                number2.getTwo();
            }).start();

//        new Thread(()->{
//
//            number.getThree();
//        }).start();
    }
}

class  Number{

    public static synchronized void getOne(){
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("one");
    }

    public  static synchronized void getTwo(){
        System.out.println("two");
    }

//    public void getThree(){
//        System.out.println("three");
//    }
}

结果:
one
two
总结:
	线程8锁 关键:
		1.非静态方法的锁 默认为 this  静态方法的锁 对应的 Class 实例 xxx.class
		2.某一个时刻内 只能有一个线程持有锁 无论几个方法

线程池

为什么使用线程池呢??
	之前使用线程 是 new Thread 的方式 
	这样是 需要就创建一个线程 
	实际上就是 创建线程  然后销毁线程 
	如果频繁的创建和销毁的话,
	那么也是非常耗费资源的。

那么 你一定使用过数据库的连接池 。
为什么你使用它呢?
	性能好呀
	为什么好呢?
		1.不是频繁的创建和销毁
		2.是去 线程池里面 取连接就好 用完放回去 (池子里 先准备好 一些连接)
线程池:1.5之后   线程的使用和调度的 接口 是 EXecutor 
	1.提供了一个线程队列  存的是 所有等待状态的线程
	 避免创建和销毁的开销 提高效率
	 2.体系结构:
	 	 1.Executor : 使用+调度
	 	 2.ExecutorService :线程池的主要接口
	 		 3.ThreadPoolExecutor : 线程池的实现类
	 	 	 4.ScheduledExecutorSerivce : 线程的调度 
	 	 		5.ScheduledThreadPollExecutor:实现了4 继承了3   
	 	 				具备线程池和线程的调度的功能
	3.工具类:Executors   提供了很多方法!!  
		eg:
			newFixedThreadPoll()  创建固定大小的线程池
			newCachedThreadPoll() 线程池的数量不固定 可以根据需求自动更改数量
			newSingleThreadExecutor() 创建单个线程池 线程池里只有一个线程
			newScheduledThreadPoll() 创建固定大小的线程 可以延迟定时 的执行任务			 	 
package com.juc;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPollApp {

    public static void main(String[] args) {


        Poll poll = new Poll();

       //1.创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(5);

        //2.为线程池中的线程  分配任务
        executorService.submit(new Thread(()->{

            while (poll.i < 100) {
                System.out.println(Thread.currentThread().getName()+" : " + poll.i++);
            }
        }));


        //3.关闭线程池
        /**
         * shutdown :
         *     等待 现有的线程池中的 线程任务完成之后 再关闭 来新的资源 也不接受了
         *
         * shutdownNow:
         *    立即关闭
         */
        executorService.shutdown();

    }
}

class Poll{
    int i =0;

}
结果:
pool-1-thread-1 : 1
pool-1-thread-1 : 2
pool-1-thread-1 : 3
pool-1-thread-1 : 4
pool-1-thread-1 : 5
pool-1-thread-1 : 6
pool-1-thread-1 : 7
pool-1-thread-1 : 8
pool-1-thread-1 : 9
pool-1-thread-1 : 10
pool-1-thread-1 : 11
pool-1-thread-1 : 12
pool-1-thread-1 : 13
pool-1-thread-1 : 14
pool-1-thread-1 : 15
pool-1-thread-1 : 16
pool-1-thread-1 : 17
pool-1-thread-1 : 18
pool-1-thread-1 : 19
。。。


 executorService.submit(new Thread(()->{

            while (poll.i < 100) {
                System.out.println(Thread.currentThread().getName()+" : " + poll.i++);
            }
        }));

只有一个一个线程 分配任务 
package com.juc;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPollApp {

    public static void main(String[] args) {


        Poll poll = new Poll();

       //1.创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(5);

        //2.为线程池中的线程  分配任务
        for (int i = 0; i < 10; i++) {

            executorService.submit(new Thread(()->{

                while (poll.i < 100) {
                    System.out.println(Thread.currentThread().getName()+" : " + poll.i++);
                }
            }));
        }
        
        //3.关闭线程池
        /**
         * shutdown :
         *     等待 现有的线程池中的 线程任务完成之后 再关闭 来新的资源 也不接受了
         *
         * shutdownNow:
         *    立即关闭
         */
        executorService.shutdown();

    }
}

class Poll{
    int i =0;

}
结果:
pool-1-thread-2 : 1
pool-1-thread-4 : 3
pool-1-thread-4 : 5
pool-1-thread-4 : 6
pool-1-thread-4 : 8
pool-1-thread-4 : 9
pool-1-thread-3 : 2
pool-1-thread-3 : 11
pool-1-thread-3 : 12
pool-1-thread-3 : 13
pool-1-thread-3 : 14
pool-1-thread-3 : 15
pool-1-thread-3 : 16
pool-1-thread-3 : 17
pool-1-thread-3 : 18
pool-1-thread-3 : 19
pool-1-thread-3 : 20
pool-1-thread-3 : 21
pool-1-thread-3 : 22
pool-1-thread-3 : 23
pool-1-thread-3 : 24
pool-1-thread-3 : 25
pool-1-thread-3 : 26
pool-1-thread-3 : 27
pool-1-thread-3 : 28
pool-1-thread-3 : 29
pool-1-thread-1 : 0
pool-1-thread-1 : 31
pool-1-thread-1 : 32
pool-1-thread-1 : 33
pool-1-thread-1 : 34
pool-1-thread-1 : 35
pool-1-thread-1 : 36
pool-1-thread-1 : 37
pool-1-thread-1 : 38
pool-1-thread-1 : 39
pool-1-thread-1 : 40
pool-1-thread-3 : 30
pool-1-thread-3 : 42
pool-1-thread-3 : 43
pool-1-thread-3 : 44
pool-1-thread-3 : 45
pool-1-thread-3 : 46
pool-1-thread-4 : 10
pool-1-thread-4 : 48
pool-1-thread-4 : 49
pool-1-thread-4 : 50
pool-1-thread-5 : 7
pool-1-thread-5 : 52
pool-1-thread-2 : 4
pool-1-thread-2 : 54
pool-1-thread-2 : 55
pool-1-thread-2 : 56
pool-1-thread-2 : 57
pool-1-thread-2 : 58
pool-1-thread-2 : 59
pool-1-thread-2 : 60
pool-1-thread-2 : 61
pool-1-thread-2 : 62
pool-1-thread-2 : 63
pool-1-thread-2 : 64
pool-1-thread-2 : 65
pool-1-thread-2 : 66
pool-1-thread-2 : 67
pool-1-thread-5 : 53
pool-1-thread-5 : 69
pool-1-thread-4 : 51
pool-1-thread-4 : 71
pool-1-thread-4 : 72
pool-1-thread-3 : 47
pool-1-thread-3 : 74
pool-1-thread-3 : 75
pool-1-thread-3 : 76
pool-1-thread-3 : 77
pool-1-thread-3 : 78
pool-1-thread-3 : 79
pool-1-thread-1 : 41
pool-1-thread-1 : 81
pool-1-thread-1 : 82
pool-1-thread-1 : 83
pool-1-thread-1 : 84
pool-1-thread-1 : 85
pool-1-thread-1 : 86
pool-1-thread-1 : 87
pool-1-thread-1 : 88
pool-1-thread-1 : 89
pool-1-thread-1 : 90
pool-1-thread-1 : 91
pool-1-thread-3 : 80
pool-1-thread-4 : 73
pool-1-thread-5 : 70
pool-1-thread-2 : 68
pool-1-thread-5 : 95
pool-1-thread-4 : 94
pool-1-thread-3 : 93
pool-1-thread-1 : 92
pool-1-thread-3 : 99
pool-1-thread-4 : 98
pool-1-thread-5 : 97
pool-1-thread-2 : 96
pool-1-thread-5:
	池1:   pool-1
	线程5: thread-5

明白了吗?
	线程池里面 5个线程   
	我分配了 10个任务 
callable:

package com.juc;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

public class ThreadPollApp {

    public static void main(String[] args) throws ExecutionException, InterruptedException {


        Poll poll = new Poll();

       //1.创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(5);


        List<Future<Integer>> list = new ArrayList<>();

        //2.为线程池中的线程  分配任务

        for (int j = 0; j < 10; j++) {

            Future<Integer> future = executorService.submit(new Callable<Integer>() {
                @Override
                public Integer call() throws Exception {

                    int sum = 0;

                    for (int i = 0; i < 100; i++) {
                        sum += i;
                    }

                    return sum;
                }
            });

            list.add(future);

        }


        //遍历10个任务的结果
        for (Future<Integer>  future: list){

            System.out.println(future.get());

        }


        //2.为线程池中的线程  分配任务
//        for (int i = 0; i < 10; i++) {
//
//            executorService.submit(new Thread(()->{
//
//                while (poll.i < 100) {
//                    System.out.println(Thread.currentThread().getName()+" : " + poll.i++);
//                }
//            }));
//        }

        //3.关闭线程池
        /**
         * shutdown :
         *     等待 现有的线程池中的 线程任务完成之后 再关闭 来新的资源 也不接受了
         *
         * shutdownNow:
         *    立即关闭
         */
        executorService.shutdown();

    }
}

class Poll{
    int i =0;

}
结果:
4950
4950
4950
4950
4950
4950
4950
4950
4950
4950

线程池+调度

package com.juc;

import java.util.concurrent.*;

public class ScheduledThreadPoolApp {
    public static void main(String[] args) throws ExecutionException, InterruptedException {

        ScheduledExecutorService pool = Executors.newScheduledThreadPool(5);


        for (int i = 0; i < 10; i++) {
            Future<Integer> future = pool.schedule(new Callable<Integer>() {
                @Override
                public Integer call() throws Exception {

                    int num = (int) (Math.random() * 101);
                    System.out.println(Thread.currentThread().getName() + " : " + num);
                    return num;
                }
            }, 1, TimeUnit.SECONDS);


            System.out.println(future.get());

        }


        pool.shutdown();

    }
}


结果:
pool-1-thread-1 : 12
12
pool-1-thread-1 : 69
69
pool-1-thread-2 : 39
39
pool-1-thread-1 : 28
28
pool-1-thread-3 : 79
79
pool-1-thread-2 : 17
17
pool-1-thread-4 : 78
78
pool-1-thread-1 : 5
5
pool-1-thread-5 : 62
62
pool-1-thread-3 : 32
32

ForkJoinPool 分支/合并

思想:
	1.任务 递归分配成若干 小任务(拆到不可再拆)
	2.小任务 并行求值
	3.结果合并

在这里插入图片描述

工作窃取:
	之前线程池:
		1.4个内核  
			1号和4号 假如发生线程阻塞
			2号和3号 执行完任务  
			那么 23是空闲状态
			cpu没有更加合理的利用 
jdk1.7之后 forkjoin:
	工作窃取模式 :
		把大任务拆分成小任务 ,把小任务 分配到不同的线程中
		形成一个线程队列(里面是小任务)是双端队列  就意味着 
		一旦某一个线程 获取任务的时候 获取不到时候 会发生阻塞 避免阻塞发生 
		这个线程 会去别的线程 队列的末尾 偷一个任务进行执行!!

更好的利用cpu资源 效率高 !!
	cpu几个 就有用几个线程

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章