解决线程安全问题: 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)