线程学习补充

解决线程安全问题:

1.synchronized隐式锁
    同步代码块
    同步方法
2.JDK1.5后
    同步锁Lock   lock()方方法上锁  必须要,unlock 方法解锁
    private Lock lock=new ReentranLock();
    public void run(){
        while(true){
            lock.lock();//上锁
            try{
                if(tick>0){
                    try{
                        Thread.sleep(200);
                    }catch(InterruptedException e){
                    }
                    sysytem.out.println(Thread.currentThread().getName());
                }                
            }finally{
                lock.unlock();//释放锁
            }
        }    
    }
    
1,线程交替打印 lock示例:condition控制线程通信
public class TestABCAlternate{
    public static void main(String[] args){
        AlternateDemo ad=new AlternateDemo();
        new Thread(new Runnable(){
            public void run(){
                for(int i=1;i<=20;i++){
                    ad.loopA(i);
                }
            }
        },"A").start();
        new Thread(new Runnable(){
            public void run(){
                for(int i=1;i<=20;i++){
                    ad.loopB(i);
                }
            }
        },"B").start();
        new Thread(new Runnable(){
            public void run(){
                for(int i=1;i<=20;i++){
                    ad.loopC(i);
                }
            }
        },"C").start();
    }
}
class AlternateDemo{
    private int number=1;//当前正在执行线程的标记
    private Lock lock=new ReentranLock();
    private Condition condition1=lock.newCondition();
    private Condition condition2=lock.newCondition();
    private Condition condition3=lock.newCondition();    
    public void loopA(){
        lock.lock();
        try{
            if(number!=1){
                condition1.await();//等待,,说明不属于1 打印
            }
            for(int i=1;i<=1;i++){
                system.out.println(Thread.currentThread().getName()+ i +totalLoop);
            }
            number=2;
            condition2.signal();//唤醒2        
        }catch(Exception e){
        
        }finally{
            lock.unlock();
        }    
    }
    public void loopB(){
        lock.lock();
        try{
            if(number!=1){
                condition1.await();//等待,,说明不属于1 打印
            }
            for(int i=1;i<=1;i++){
                system.out.println(Thread.currentThread().getName()+ i +totalLoop);
            }
            number=3;
            condition3.signal();//唤醒2       
        }catch(Exception e){    
        }finally{
            lock.unlock();
        }    
    }
    public void loopC(){
        lock.lock();
        try{
            if(number!=1){
                condition1.await();//等待,,说明不属于1 打印
            }
            for(int i=1;i<=1;i++){
                system.out.println(Thread.currentThread().getName()+ i +totalLoop);
            }
            number=1;
            condition1.signal();//唤醒2        
        }catch(Exception e){        
        }finally{
            lock.unlock();
        }    
    }    
}
    
读写锁:ReadWriteLock  写写/读写  需要互斥
    读可以允许多个线程操作
    写只能有一个线程操作
class ReadWriteLockDemo{
    private int number=0;
    private ReadWriteLock lock=new ReentranReadWriteLock();//创建读写锁
    
    //读
    public void get(){
        lock.readLock.lock();//上锁
        try{
            system.out.println(number);
        }finally{
            lock.readLock.unlock();//释放锁
        }
    }    
    //写
    public void set(int number){
        lock.writeLock.lock();
        try{
            system.out.println(number);
        }finally{
            lock.writeLock.unlock();//释放锁
        }
    }    
}    
    
1.两个普通同步方法,两个线程,标准打印?one  two
2.新增Thread.sleep()给getOne(),打印? one  two 
3.新增普通同步方法getThread(),打印? one two
4.两个普通同步方法,两个number对象,打印?two  one 
5.修改getOne()为静态同步方法,一个number对象?two one
6.修改两个方法均为静态同步方法,一个number对象?one  two
7.一个静态同步方法,一个非静态同步方法,两个number对象?two  one 
8.两个静态同步方法,两个number对象?one  two

线程八锁的关键:
1.非静态方法的锁默认为this,静态方法的锁为对应的class实例
2.某一个时刻内,只能有一个线程持有锁,无论几个方法。
    
    
一、线程池:
    提供了一个线程队列,队列中保存着所有等待状态的线程,
    避免了创建与销毁开销,提高了响应速度。
二、线程池的体系结构
    java.util.concurrent.Executor:负责线程的使用与调度的根接口
        ExecutorService子接口:线程池的主要接口
            ThreadPoolExecutor 线程池的实现类
            ScheduledExecutorService 子接口:负责线程的调度
                ScheduledThreadPollExecutor:继承ThreadPoolExecutor,实现ScheduledExecutorService
三、工具类 Executors
        ExecutorService  newFixedThreadPool();创建固定大小的线程池
        ExecutorService  newCachedThreadPool();缓存线程池,线程池的数量不固定,可以根据需求自动的更改数量
        ExecutorService  newSingleThreadExecutor();创建单个线程池,线程池中只有一个线程
     
     ScheduledExecutorService  newScheduledThreadPool();创建固定大小的线程,可以延迟或定时的执行任务。
public class TestThreadPool{
    public static void main(String[] args){
        //1.创建线程池  固定大小线程池
        ExecutorService pool=Executors.newFixedThreadPool(5);
        ThreadPoolDemo ted=new ThreadPoolDemo();
        //2.为线程池中的线程分配任务
        pool.submit(ted);
        //3.关闭线程池
        pool.shutdown();
        
    }

    class ThreadPoolDemo implements Runnable{
        private int i=0;
        public void run(){
            while(i<100){
                i++;
                system.out.println("");
            }
        }    
    }
    
    Callable位于java.util.concurrent包下,它也是一个接口,在它里面也只声明了一个方法,只不过这个方法叫做call()
    Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果。
    必要时可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果
    
    
    创建执行线程的方式三:
        1.实现Callable接口,相较于实现Runnable接口的方式,方式可以有返回值,并且可以抛出异常。
        2.执行callable方式,需要FutureTask实现类的支持,用于接收运算结果,FutureTask是Future接口的实现类
    class SumTask implements Callable<Long> {

        @Override
        public Long call() throws Exception {

            long sum = 0;
            for (int i = 0; i < 9000; i++) {
                sum += i;
            }
            return sum;
        }

        public static void main(String[] args) throws ExecutionException, InterruptedException {
            System.out.println("Start:" + System.nanoTime());
            // 将Callable写的任务封装到一个由执行者调度的FutureTask对象
            FutureTask<Long> futureTask = new FutureTask<Long>(new SumTask());
            // 创建线程池并返回ExecutorService实例 
            Executor executor=Executors.newSingleThreadExecutor();
            //执行任务
            executor.execute(futureTask);
            //打印输出返回值
            System.out.println(futureTask.get());
            System.out.println("End:" + System.nanoTime());
    }

} 
注意点:

避免使用Executors创建线程池,主要是避免使用其中的默认实现,那么我们可以自己直接调用ThreadPoolExecutor的构造函数来自己创建线程池。
在创建的同时,给BlockQueue指定容量就可以了。
private static ExecutorService executor = new ThreadPoolExecutor(10, 10,
60L, TimeUnit.SECONDS,
new ArrayBlockingQueue(10));
这种情况下,一旦提交的线程数超过当前可用线程数时,就会抛出java.util.concurrent.RejectedExecutionException,
这是因为当前线程池使用的队列是有边界队列,队列已经满了便无法继续处理新的请求。
但是异常(Exception)总比发生错误(Error)要好

ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)







原文地址:https://www.cnblogs.com/qiuxiaoliang/p/9868897.html