多线程和并发库

创建线程的2种方法

运用多态机制 创建Thread的子类对象 thread1 并且覆盖父类的run方法
Thread thread = new Thread(){public void run(){}}
多态的概念 thread 是 Thrad的一个子类
Thread 在start()后调用run(),该run方法 先判断是否有Runable 参数 有则 调用 Runable.run() 没有则往下执行其他代码
如果是 子类 覆盖了run() 则不会去找Runable 直接执行子类的run()
此时对象可以直接使用start方法启动线程

Thread thread1=new Thread() {            

            public void run() {
                while(true) {
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(this.getName());
                }               
            }
        };
        thread1.start();

package thread;

public class demo_1 {
    public static void main(String[] args) {
        cat c=new cat();
        c.start();
    }
}
class cat extends Thread{
    public void run() {
        while(true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        System.out.println("11111");
    }
    }
}

如果是实现runable接口 则需要把对象传入Thread 后
对象才可调用run启动线程
dog d=new dog();
Thread t=new Thread(d);
d.run();
即覆盖实现了Ruable的类d
等价于Thread t=new Thread(new dog().run());

package thread;

public class demo_2 {
    public static void main(String[] args) {
        dog d=new dog();
        Thread t=new Thread(d);
        d.run();
    }
}
class dog implements Runnable{
    public void run() {
        while(true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        System.out.println("11111");
    }
    }
}

线程通信 wait() notify()

wait 和 nitify 方法属于类而非线程独有
功能:实现子线程输出10次 主线程main输出10次 如此循环往复50次
思路:
因为子线程先输出 所以子线程的输出逻辑应该在主线程之前
用一个boolean控制子线程和main线程能否开启
各自线程在执行完自己的逻辑后用notify 唤醒其他线程

import java.util.concurrent.atomic.AtomicInteger;

public class TraditionalThreadCommunication {

public static void main(String[] args) {

    final Business business = new Business();
    new Thread(
            new Runnable() {

                @Override
                public void run() {

                    for(int i=1;i<=50;i++){
                        business.sub(i);
                    }

                }
            }
    ).start();

    for(int i=1;i<=50;i++){
        business.main(i);
    }

}
}
//需要同步的代码放在同一个类 由同一个类(锁)控制访问
class Business {
private boolean bShouldSub = true;
public synchronized void sub(int i){
while(!bShouldSub){
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for(int j=1;j<=10;j++){
System.out.println("sub thread sequence of " + j + ",loop of " + i);
}
bShouldSub = false;
this.notify();
}

  public synchronized void main(int i){
        while(bShouldSub){
            try {
                this.wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        for(int j=1;j<=10;j++){
            System.out.println("main thread sequence of " + j + ",loop of " + i);
        }
        bShouldSub = true;
        this.notify();
  }
}

线程范围的数据共享(用HashMap版)

功能:使用HashMap实现仅在单个线程内数据共享
思路:把每个线程的线程作为key 数据作为value存入map

import java.util.HashMap;
import java.util.Map;
import java.util.Random;

public class ThreadScopeShareData {

    private static int data = 0;
    private static Map<Thread, Integer> threadData = new HashMap<Thread, Integer>();
    public static void main(String[] args) {
        for(int i=0;i<40;i++){
            new Thread(new Runnable(){
                @Override
                public void run() {
                     data = new Random().nextInt();

                    System.out.println(Thread.currentThread().getName() 
                            + " has put data :" + data);
                    //把每个线程的数据单独保存起来 否则当线程创建后run方法运行一半 
                    //其他线程可能会修改了本线程的数据
                    threadData.put(Thread.currentThread(), data);
                    new A().get();
                    new B().get();
                }
            }).start();
/*          try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }*/
        }
    }

    static class A{
        public void get(){
            int data = threadData.get(Thread.currentThread());
            System.out.println("A from " + Thread.currentThread().getName() 
                    + " get data :" + data);
        }
    }

    static class B{
        public void get(){
            int data = threadData.get(Thread.currentThread());          
            System.out.println("B from " + Thread.currentThread().getName() 
                    + " get data :" + data);
        }       
    }
}

使用ThreadLocal实现线程范围内数据共享

ThreadLocal在线程结束时便清空

import java.util.HashMap;
import java.util.Map;
import java.util.Random;

public class ThreadLocalTest {
    public static void main(String[] args) {
        for(int i=0;i<2;i++){
            new Thread(new Runnable(){
                @Override
                public void run() {
                    int data = new Random().nextInt();
                    MyThreadScopeData.getThreadInstance().setName("name" + data);
                    MyThreadScopeData.getThreadInstance().setAge(data);
                    new A().get();
                    new B().get();
                }
            }).start();
        }
    }

    static class A{
        public void get(){
                    MyThreadScopeData myData =MyThreadScopeData.getThreadInstance();
            System.out.println("A from " + Thread.currentThread().getName() 
                    + " getMyData: " + myData.getName() + "," +
                    myData.getAge());
        }
    }

    static class B{
        public void get(){  
            MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();
            System.out.println("B from " + Thread.currentThread().getName() 
                    + " getMyData: " + myData.getName() + "," +
                    myData.getAge());           
        }       
    }
}

class MyThreadScopeData{
    private MyThreadScopeData(){}
    public static /*synchronized*/ MyThreadScopeData getThreadInstance(){
    //该instance保留到当前线程死亡为止 系统自动clear
        MyThreadScopeData instance = map.get();
        if(instance == null){
            instance = new MyThreadScopeData();
            map.set(instance);
        }
        return instance;
    }
    private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<MyThreadScopeData>();

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

线程间共享数据

public class MultiThreadShareData {
    private static ShareData1 data1 = new ShareData1();
    public static void main(String[] args) {
        ShareData1 data2 = new ShareData1();
        //自定义的Runable方法,继承了Runable接口
        new Thread(new MyRunnable1(data2)).start();
        new Thread(new MyRunnable2(data2)).start();     
    }
}   
    class MyRunnable1 implements Runnable{
        private ShareData1 data1;
        public MyRunnable1(ShareData1 data1){
            this.data1 = data1;
        }
        public void run() {
            data1.decrement();          
        }
    }

    class MyRunnable2 implements Runnable{
        private ShareData1 data1;
        public MyRunnable2(ShareData1 data1){
            this.data1 = data1;
        }
        public void run() {
            data1.increment();
        }
    }

    class ShareData1{
        private int j = 0;
        public synchronized void increment(){
            j++;
        }       
        public synchronized void decrement(){
            j--;
        }
    }

3种线程池

只需要调用线程池的excute()方法即可启动线程

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class ThreadPoolTest {
    public static void main(String[] args) {
        //线程池 自定义每次只能同时执行3个线程
        ExecutorService threadPool = Executors.newFixedThreadPool(3);
        //缓存线程池 可根据需要动态变化 可同时执行的线程数量
        //ExecutorService threadPool = Executors.newCachedThreadPool();
        //单线程池 线程死亡自动启动另一个线程 保证线程池有线程在运行
        //ExecutorService threadPool = Executors.newSingleThreadExecutor();
        for(int i=1;i<=10;i++){
            final int task = i;
            threadPool.execute(new Runnable(){
                @Override
                public void run() {
                    for(int j=1;j<=10;j++){
                        try {
                            Thread.sleep(20);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                        System.out.println(/*Thread.currentThread().getName() +"  of"+*/" task  "+ task +" has loop  " + j + " times   " );
                    }
                }
            });
        }

        //以上代码虽然让线程以启动 但每个线程的run方法在执行的同时 以下的代码也同时执行
        //如果此时调用shutdownNow()方法,很有可能会让执行一半的run方法停止 从而运行时报线程本打断的错误
        //threadPool.shutdownNow();
        //改为调用次方法 当全部线程空闲才关闭线程池
        threadPool.shutdown();
        System.out.println("all of 10 tasks have committed! ");

        //定时器 6s后执行 每个2s执行一次 缺点只能定制几秒以后 可以用目标时间减去此刻时间实现
        Executors.newScheduledThreadPool(3).scheduleAtFixedRate(new Runnable(){
            public void run() {System.out.println("bombing!");}
            },6,2,TimeUnit.SECONDS);
    }

}

Callable and Future

package cn.itcast.heima2;

import java.util.Random;
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;
import java.util.concurrent.TimeUnit;
public class CallableAndFuture {
    public static void main(String[] args) {

        //future有什么用 ?等一会取得线程的执行结果
        ExecutorService threadPool =  Executors.newSingleThreadExecutor();
        Future<String> future =
            threadPool.submit(
                new Callable<String>() {
                    public String call() throws Exception {
                        Thread.sleep(2000);
                        return "hello";
                    };
                }
        );
        System.out.println("等待结果");
        try {
            //1s之内没有取得结果则报错
            System.out.println("拿到结果:" + future.get(1000,TimeUnit.SECONDS));
        } catch (Exception e) {
            e.printStackTrace();
        }

         //对线程池中的线程 先执行完的结果先被获取
        //类似qq农场 那块才熟了收哪块
        ExecutorService threadPool2 =  Executors.newFixedThreadPool(10);
        CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(threadPool2);
        for(int i=1;i<=10;i++){
            final int seq = i;
            completionService.submit(new Callable<Integer>() {
                @Override
                public Integer call() throws Exception {
                    Thread.sleep(new Random().nextInt(5000));
                    return seq;
                }
            });
        }
        for(int i=0;i<10;i++){
            try {
                System.out.println(
                        completionService.take().get());
            }  catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

lock

lock方法不属于线程 每个类可以使用lock来实现同步

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockTest {
    public static void main(String[] args) {
        new LockTest().init();
    }
    private void init(){
        final Outputer outputer = new Outputer();
        new Thread(new Runnable(){
            @Override
            public void run() {
                while(true){
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    outputer.output("zhangxiaoxiang");
                }

            }
        }).start();

        new Thread(new Runnable(){
            @Override
            public void run() {
                while(true){
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    outputer.output("lihuoming");
                }

            }
        }).start();

    }

    static class Outputer{
        Lock lock = new ReentrantLock();
        public void output(String name){
            int len = name.length();
            lock.lock();
            //用try的原因 防止 syso语句异常 没有解锁 造成死锁
            try{
                for(int i=0;i<len;i++){
                    System.out.print(name.charAt(i));
                }
                System.out.println();
            }finally{
                lock.unlock();
            }
        }

        public synchronized void output2(String name){
            int len = name.length();
            for(int i=0;i<len;i++){
                    System.out.print(name.charAt(i));
            }
            System.out.println();
        }

        public static synchronized void output3(String name){
            int len = name.length();
            for(int i=0;i<len;i++){
                    System.out.print(name.charAt(i));
            }
            System.out.println();
        }   
    }
}

读写锁

读写锁不是属于线程的 而是属于类

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

public class ReadWriteLockTest {
    public static void main(String[] args) {
        final Queue3 q3 = new Queue3();
        for(int i=0;i<3;i++)
        {
            new Thread(){
                public void run(){
                    while(true){
                        q3.get();                       
                    }
                }

            }.start();

            new Thread(){
                public void run(){
                    while(true){
                        q3.put(new Random().nextInt(10000));
                    }
                }           

            }.start();
        }

    }
}

class Queue3{
    private Object data = null;//共享数据,只能有一个线程能写该数据,但可以有多个线程同时读该数据。
    ReadWriteLock rwl = new ReentrantReadWriteLock();
    public void get(){
        //读锁 能同时访问 但是 当第一个线程读的时候数据为空
        //则它会解开读锁 再为当前数据加上写锁 其他线程无法访问直至第一个线程从
        //数据库获取到了数据并传入给了该被读取的变量
        rwl.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + " be ready to read data!");
            Thread.sleep((long)(Math.random()*1000));
            System.out.println(Thread.currentThread().getName() + "have read data :" + data);           
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally{
            rwl.readLock().unlock();
        }
    }

    public void put(Object data){
        //写锁 不能同时访问
        rwl.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + " be ready to write data!");                  
            Thread.sleep((long)(Math.random()*1000));
            this.data = data;       
            System.out.println(Thread.currentThread().getName() + " have write data: " + data);                 
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally{
            rwl.writeLock().unlock();
        }

    }
}

缓存的原理

缓存的原理 从map里根据key读取数据加读锁
如果map里没有,则解开读锁 加上写锁 从数据库读取并写入缓存 
然后写锁解开 加上读锁
注意:因为可能有多个线程同时运行到 解开读锁这一步 此时不需要都去数据库读取数据 只需读取一次即可 所以仍然需要再次判读是否有线程抢先读取了

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

public class CacheDemo {

    private Map<String, Object> cache = new HashMap<String, Object>();
    public static void main(String[] args) {

    }
    //加锁的原因:如果有多个线程同时访问且当前数据为空 则都会去数据库get 重复执行了
    //如果数据为空 则把读锁解开 把写锁加上 从数据库获取数据后 写锁解开 还原为读锁
    private ReadWriteLock rwl = new ReentrantReadWriteLock();
    public  Object getData(String key){
        rwl.readLock().lock();
        Object value = null;
        try{
            value = cache.get(key);
            if(value == null){
                rwl.readLock().unlock();
                rwl.writeLock().lock();
                try{
                    //这里再次判断数据是否为空的原因:是因为可能出现多个线程已经执行到了上面的rwl.writeLock().lock();语句
                    //如果没有再次判断,虽然第一个线程已经获取了数据,下一个线程也会再次从数据库获取数据
                    if(value==null){
                        value = "aaaa";//实际是去queryDB();
                    }
                }finally{
                    rwl.writeLock().unlock();
                }
                rwl.readLock().lock();
            }
        }finally{
            rwl.readLock().unlock();
        }
        return value;
    }
}

condition.await()和condition.signal()

condition.await()和condition.signal()类似于 wait 和notify 但后者只能写在synchornized中 前者只能在lock对象中。且能唤醒指定的线程>>> 详情见三个线程的互相通信

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ConditionCommunication {
    public static void main(String[] args) {
        final Business business = new Business();
        new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        for(int i=1;i<=50;i++){
                            business.sub(i);
                        }
                    }
                }
        ).start();

        for(int i=1;i<=50;i++){
            business.main(i);
        }
    }
    static class Business {
            Lock lock = new ReentrantLock();
            Condition condition = lock.newCondition();
          private boolean bShouldSub = true;
          public  void sub(int i){
              lock.lock();
              try{
                  while(!bShouldSub){
                      try {
                        condition.await();
                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                  }
                    for(int j=1;j<=10;j++){
                        System.out.println("sub thread sequence of " + j + ",loop of " + i);
                    }
                  bShouldSub = false;
                  condition.signal();
              }finally{
                  lock.unlock();
              }
          }

          public  void main(int i){
              lock.lock();
              try{
                 while(bShouldSub){
                        try {
                            condition.await();
                        } catch (Exception e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                    for(int j=1;j<=100;j++){
                        System.out.println("main thread sequence of " + j + ",loop of " + i);
                    }
                    bShouldSub = true;
                    condition.signal();
          }finally{
              lock.unlock();
          }
      }

    }
}

三个线程互相通信 线程1启动线程2 2启动3 3启动1

思路:
在类中定义三个condictuon
Lock lock = new ReentrantLock();
Condition condition1 = lock.newCondition();
Condition condition2 = lock.newCondition();
Condition condition3 = lock.newCondition();
然后每个方法使用一个condiction

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ThreeConditionCommunication {

    public static void main(String[] args) {
        final Business business = new Business();
        new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        for(int i=1;i<=50;i++){
                            business.sub2(i);
                        }
                    }
                }
        ).start();

        new Thread(
                new Runnable() {

                    @Override
                    public void run() {

                        for(int i=1;i<=50;i++){
                            business.sub3(i);
                        }

                    }
                }
        ).start();      

        for(int i=1;i<=50;i++){
            business.main(i);
        }

    }

    static class Business {
            Lock lock = new ReentrantLock();
            Condition condition1 = lock.newCondition();
            Condition condition2 = lock.newCondition();
            Condition condition3 = lock.newCondition();
          private int shouldSub = 1;
          public  void sub2(int i){
              lock.lock();
              try{
                  while(shouldSub != 2){
                      try {
                        condition2.await();
                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                  }
                    for(int j=1;j<=10;j++){
                        System.out.println("sub2 thread sequence of " + j + ",loop of " + i);
                    }
                  shouldSub = 3;
                  condition3.signal();
              }finally{
                  lock.unlock();
              }
          }

          public  void sub3(int i){
              lock.lock();
              try{
                  while(shouldSub != 3){
                      try {
                        condition3.await();
                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                  }
                    for(int j=1;j<=20;j++){
                        System.out.println("sub3 thread sequence of " + j + ",loop of " + i);
                    }
                  shouldSub = 1;
                  condition1.signal();
              }finally{
                  lock.unlock();
              }
          }       

          public  void main(int i){
              lock.lock();
              try{
                 while(shouldSub != 1){
                        try {
                            condition1.await();
                        } catch (Exception e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                    for(int j=1;j<=100;j++){
                        System.out.println("main thread sequence of " + j + ",loop of " + i);
                    }
                    shouldSub = 2;
                    condition2.signal();
          }finally{
              lock.unlock();
          }
      }

    }
}

控制能同时有几个线程并发Semaphore

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

public class SemaphoreTest {
    public static void main(String[] args) {
        ExecutorService service = Executors.newCachedThreadPool();
        final  Semaphore sp = new Semaphore(5);
        for(int i=0;i<10;i++){
            Runnable runnable = new Runnable(){
                    public void run(){
                    try {
                        sp.acquire();
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }
                    System.out.println("线程" + Thread.currentThread().getName() + 
                            "进入,当前已有" + (5-sp.availablePermits()) + "个并发");
                    try {
                        Thread.sleep((long)(Math.random()*10000));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("线程" + Thread.currentThread().getName() + 
                            "即将离开");                    
                    sp.release();
                    //下面代码有时候执行不准确,因为其没有和上面的代码合成原子单元
                    System.out.println("线程" + Thread.currentThread().getName() + 
                            "已离开,当前已有" + (3-sp.availablePermits()) + "个并发");                    
                }
            };
            service.execute(runnable);          
        }
    }

}

控制只有3个线程同时完成后线程才能继续执行

控制只有在线程池中3个线程都完成到达cb.wait()时,线程才同时继续运行

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

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 runnable = new Runnable(){
                    public void run(){
                    try {
                        Thread.sleep((long)(Math.random()*10000));  
                        System.out.println("线程" + Thread.currentThread().getName() + 
                                "即将到达集合地点1,当前已有" + (cb.getNumberWaiting()+1) + "个已经到达," + (cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候"));                       
                        cb.await();

                        Thread.sleep((long)(Math.random()*10000));  
                        System.out.println("线程" + Thread.currentThread().getName() + 
                                "即将到达集合地点2,当前已有" + (cb.getNumberWaiting()+1) + "个已经到达," + (cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候"));
                        cb.await(); 
                        Thread.sleep((long)(Math.random()*10000));  
                        System.out.println("线程" + Thread.currentThread().getName() + 
                                "即将到达集合地点3,当前已有" + (cb.getNumberWaiting() + 1) + "个已经到达," + (cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候"));                     
                        cb.await();                     
                    } catch (Exception e) {
                        e.printStackTrace();
                    }               
                }
            };
            service.execute(runnable);
        }
        service.shutdown();
    }
}

CountDownLatch的用法

 使用倒计时器 控制只有被唤几次才会醒
    final CountDownLatch cdOrder = new CountDownLatch(1);
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CountdownLatchTest {

    public static void main(String[] args) {
        ExecutorService service = Executors.newCachedThreadPool();
        //当处于await状态时 需要countDown1次才被唤醒
        final CountDownLatch cdOrder = new CountDownLatch(1);
        //当处于await状态时 需要countDown3次才被唤醒
        final CountDownLatch cdAnswer = new CountDownLatch(3);      
        for(int i=0;i<3;i++){
            Runnable runnable = new Runnable(){
                    public void run(){
                    try {
                        System.out.println("线程" + Thread.currentThread().getName() + 
                                "正准备接受命令");                     
                        cdOrder.await();
                        System.out.println("线程" + Thread.currentThread().getName() + 
                        "已接受命令");                               
                        Thread.sleep((long)(Math.random()*10000));  
                        System.out.println("线程" + Thread.currentThread().getName() + 
                                "回应命令处理结果");                        
                        cdAnswer.countDown();                       
                    } catch (Exception e) {
                        e.printStackTrace();
                    }               
                }
            };
            service.execute(runnable);
        }       
        try {
            Thread.sleep((long)(Math.random()*10000));

            System.out.println("线程" + Thread.currentThread().getName() + 
                    "即将发布命令");                      
            cdOrder.countDown();
            System.out.println("线程" + Thread.currentThread().getName() + 
            "已发送命令,正在等待结果");    
            cdAnswer.await();
            System.out.println("线程" + Thread.currentThread().getName() + 
            "已收到所有响应结果");   
        } catch (Exception e) {
            e.printStackTrace();
        }               
        service.shutdown();

    }
}

线程间使用Exchanger交换数据

将数据都放在同一个Exchanger中进行2个线程间的数据交换

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

public class ExchangerTest {

    public static void main(String[] args) {
        ExecutorService service = Executors.newCachedThreadPool();
        final Exchanger exchanger = new Exchanger();
        service.execute(new Runnable(){
            public void run() {
                try {               

                    String data1 = "zxx";
                    System.out.println("a线程" + Thread.currentThread().getName() + 
                    "正在把数据" + data1 +"换出去");
                    Thread.sleep((long)(Math.random()*10000));
                    String data2 = (String)exchanger.exchange(data1);
                    System.out.println("a线程" + Thread.currentThread().getName() + 
                    "换回的数据为" + data2);
                }catch(Exception e){

                }
            }   
        });
        service.execute(new Runnable(){
            public void run() {
                try {               

                    String data1 = "lhm";
                    System.out.println("线程" + Thread.currentThread().getName() + 
                    "正在把数据" + data1 +"换出去");
                    Thread.sleep((long)(Math.random()*10000));                  
                    String data2 = (String)exchanger.exchange(data1);
                    System.out.println("线程" + Thread.currentThread().getName() + 
                    "换回的数据为" + data2);
                }catch(Exception e){

                }               
            }   
        });     
    }
}

使用阻塞队列存取数据

存数据queue.put(1);
取数据queue.take();

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class BlockingQueueTest {
    public static void main(String[] args) {
    //自定义队列能存放3个数据
        final BlockingQueue queue = new ArrayBlockingQueue(3);
        for(int i=0;i<2;i++){
            new Thread(){
                public void run(){
                    while(true){
                        try {
                            Thread.sleep((long)(Math.random()*1000));
                            System.out.println(Thread.currentThread().getName() + "准备放数据!");                            //放数据
                            queue.put(1);
                            System.out.println(Thread.currentThread().getName() + "已经放了数据," +                           
                                        "队列目前有" + queue.size() + "个数据");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }

                    }
                }

            }.start();
        }

        new Thread(){
            public void run(){
                while(true){
                    try {
                        //将此处的睡眠时间分别改为100和1000,观察运行结果
                        Thread.sleep(1000);
                        System.out.println(Thread.currentThread().getName() + "准备取数据!");
                        //取数据
                        queue.take();
                        System.out.println(Thread.currentThread().getName() + "已经取走数据," +                           
                                "队列目前有" + queue.size() + "个数据");                    
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }

        }.start();          
    }
}

阻塞队列的通信

import java.util.Collections;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;

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

        final Business business = new Business();
        new Thread(
                new Runnable() {                
                    @Override
                    public void run() {                 
                        for(int i=1;i<=5;i++){
                            business.sub(i);
                        }                       
                    }
                }
        ).start();

        for(int i=1;i<=5;i++){
            business.main(i);
        }       
    }

     static class Business {                 
          BlockingQueue<Integer> queue1 = new ArrayBlockingQueue<Integer>(1);
          BlockingQueue<Integer> queue2 = new ArrayBlockingQueue<Integer>(1);
          //匿名构造方法 不能用静态代码块 因为queue1 queue2要在类加载时才初始化
          {
            //  Collections.synchronizedMap(null);
              try {
                  System.out.println("xxxxxdfsd把vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvsafdsa");
                queue2.put(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
          }

          public   void sub(int i){
                try {
                    queue1.put(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                for(int j=1;j<=10;j++){
                    System.out.println("sub:"+i+"["+1+"]");
                }
                try {
                    //因为queue2里没有数据,所以需要在初始化的时候先把数据放入queue2 才能把数据取出来 
                    queue2.take();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
          }

          public   void main(int i){
                try {
                    queue2.put(1);
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
                for(int j=1;j<=100;j++){
                    System.out.println("main:"+ i+"["+1+"]");
                }
                try {
                    queue1.take();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
          }
      }

}

使用CopyOnWriteArrayList可以在迭代时移除数据

如果使用ArrayList 则不能在迭代输出的时候 删除元素 否则 可能会造成死循环

1.如果在移除第一个之后 版本记录号+1 期望版本记录号不变 进入下一次while时,next() 去判断 当前版本号和except版本号不同 throws Exception

2.如果在移除第二个之后 size-1变为2 ,当进入下一次循环 cursor 加1 此时cursor等于2 hasnext 去判断cursor与 size 若相等则 while循环退出 不再读取下一个 (cursor=0指向第一个 =1指向第二个...)

3.如果移除最后一个size由3变为2 再一次进入while hasnext cursor加1变为 3 ,不等于size 继续循环 curosr 继续加 size不变 curosr永远大于size while 永远循环

综上 ArrayList 在迭代时不能移除数据
应使用CopyOnWriteArrayList

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;
public class CollectionModifyExceptionTest {
    public static void main(String[] args) {
        Collection<User> users = new CopyOnWriteArrayList<User>();

            //new ArrayList();
        users.add(new User("张三",28));   
        users.add(new User("李四",25));           
        users.add(new User("王五",31));   
        Iterator<User> itrUsers = users.iterator();
        while(itrUsers.hasNext()){
            System.out.println("aaaa");
            User user = (User)itrUsers.next();
            if("李四".equals(user.getName())){
                users.remove(user);
                //itrUsers.remove();
            } else {
                System.out.println(user);               
            }
        }
    }
}    

16条日志交由4个线程分别输出、

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class Test {

    public static void main(String[] args){
        final BlockingQueue<String> queue = new ArrayBlockingQueue<String>(1);
                //创建四个线程 同时去queue里面获取一个日志 即1s获取并打印了4条日志
        for(int i=0;i<4;i++){
            new Thread(new Runnable(){
                @Override
                public void run() {
                    while(true){
                        try {
                            String log = queue.take();
                            parseLog(log);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                }

            }).start();
        }

        System.out.println("begin:"+(System.currentTimeMillis()/1000));
        /*模拟处理16行日志,下面的代码产生了16个日志对象,当前代码需要运行16秒才能打印完这些日志。
        修改程序代码,开四个线程让这16个对象在4秒钟打完。
        */
        for(int i=0;i<16;i++){  //这行代码不能改动
            final String log = ""+(i+1);//这行代码不能改动
            {
                    try {
                        queue.put(log);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    //Test.parseLog(log);
            }
        }
    }

    //parseLog方法内部的代码不能改动
    public static void parseLog(String log){
        System.out.println(log+":"+(System.currentTimeMillis()/1000));

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

}

Semaphore

import java.util.concurrent.Semaphore;
import java.util.concurrent.SynchronousQueue;

public class Test {

    public static void main(String[] args) {
        final Semaphore semaphore = new Semaphore(1);
        final SynchronousQueue<String> queue = new SynchronousQueue<String>();
        for(int i=0;i<10;i++){
            new Thread(new Runnable(){
                @Override
                public void run() { 
                    try {
                        semaphore.acquire();
                        String input = queue.take();
                        String output = TestDo.doSome(input);
                        System.out.println(Thread.currentThread().getName()+ ":" + output);
                        semaphore.release();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }   
                }
            }).start();
        }

        System.out.println("begin:"+(System.currentTimeMillis()/1000));
        for(int i=0;i<10;i++){  //这行不能改动
            String input = i+"";  //这行不能改动
            try {
                queue.put(input);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

//不能改动此TestDo类
class TestDo {
    public static String doSome(String input){

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        String output = input + ":"+ (System.currentTimeMillis() / 1000);
        return output;
    }
}

CopyOnWriteArrayList

package syn;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;

//不能改动此Test类    
public class Test extends Thread{

    private TestDo testDo;
    private String key;
    private String value;

    public Test(String key,String key2,String value){
        this.testDo = TestDo.getInstance();
        /*常量"1"和"1"是同一个对象,下面这行代码就是要用"1"+""的方式产生新的对象,
        以实现内容没有改变,仍然相等(都还为"1"),但对象却不再是同一个的效果*/
        this.key = key+key2; 
/*      a = "1"+"";
        b = "1"+""
*/
        this.value = value;
    }

    public static void main(String[] args) throws InterruptedException{
        Test a = new Test("1","","1");
        Test b = new Test("1","","2");
        Test c = new Test("3","","3");
        Test d = new Test("4","","4");
        System.out.println("begin:"+(System.currentTimeMillis()/1000));
        a.start();
        b.start();
        c.start();
        d.start();

    }

    public void run(){
        testDo.doSome(key, value);
    }
}

class TestDo {

    private TestDo() {}
    private static TestDo _instance = new TestDo(); 
    public static TestDo getInstance() {
        return _instance;
    }
    //一个线程在迭代时,另一个线程不能对集合进行操作 改用CopyOnWriteArrayList
    //private ArrayList keys = new ArrayList();
    private CopyOnWriteArrayList keys = new CopyOnWriteArrayList();
    public void doSome(Object key, String value) {
        Object o = key;
        //判断集合是否有相同的key 没有则加入 有则将当前的o 改为集合里值和o相同的对象 因为只有对象相同的锁才能访问互斥
        if(!keys.contains(o)){
            keys.add(o);
        }else{

            for(Iterator iter=keys.iterator();iter.hasNext();){
                try {
                    Thread.sleep(20);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                Object oo = iter.next();
                if(oo.equals(o)){
                    o = oo;
                    break;
                }
            }
        }
        synchronized(o)
        // 以大括号内的是需要局部同步的代码,不能改动!
        {
            try {
                Thread.sleep(1000);
                System.out.println(key+":"+value + ":"
                        + (System.currentTimeMillis() / 1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

猜你喜欢

转载自blog.csdn.net/v2020877/article/details/82461169