多线程
## 1,线程基础 1,继承Thread方式的线程 - 当需要再此启动一个线程时,需要再创建对象,不能重复使用。 2,推荐的创建线程方式:继承Runnalbe,使用Thread类 - 1.5之前就这两种 - callable 第三种 - 可以有返回值 call() - 可以抛出异常 - 支持泛型返回值 - 需要借助FutureTask, 如获取返回值的时候 - \`\`\`java class MyThread implements Callable{ public Object call() throws Exception{ .... return null; } } MyThread thread = new MyThread(); FutureTask f = new FutureTask(thread); new Thread(f).start(); new Thread(f).start(); // 反复执行不会执行,需要定义新的task try{ Object ret = f.get();// get()为返回值,会阻塞主线程执行 }catch(InterruptedException){ }catch(Execution e){ } \`\`\` !\[image-20200906142542954\](https://i.loli.net/2020/09/06/n7BGHetabZgmRjE.png) - 线程池 第四种方式 - 提高速度,降低资源消耗 - 便于线程管理:核心池大小,最大线程数,没任务多长时间终止 \`\`\`java //Executors 工具类 //ExecutorService 接口 ExecutorService service = Executors.newFixedThreadPool(10); ThreadPoolExecutor executor = (ThreadPoolExecutor)service; executor.setxxx() //设置参数 service.execute(Runnable); service.submit(Callable); service.shutdown(); \`\`\` 3,Thread常用方法 \| getPriority() \| setPrioority(1,5,10) \| \| \| ---------------------------------- \| --------------------------------------------- \| --------- \| \| currentThread() 静态方法 \| getName() \| setName() \| \| yield() 释放cup执行权,变为就绪状态 \| join():在A线程中B.join() ,A就阻塞,B执行完到A \| \| \| stop() :过时方法,强制结束线程 \| sleep(ms) \| isAlive() \| 4,线程分类 守护线程,用户线程 守护线程服务用户线程 \`\`\`java thread.setDaemon(true) //设置为守护线程 \`\`\` - 最简单程序main主线程与gc回收线程 - 若没有用户线程jvm则结束 5,线程生命周期 - NEW : 创建对象 - RUNNABLE :运行 start - BLOCKED:阻塞 sleep,join,等待同步锁,wait,suspend:过时方法 - WAITING:wait() - TIMED-WAITING:wait(time) - TERMINATED:stop,exception,run结束 阻塞---》就绪:sleep,join结束获取同步锁,notify,resume:过时方法 6,注意 - wait:阻塞,会释放锁,必须在synchronized内 - sleep:阻塞,不会释放锁,任何时候可以 wait,notify,notifyall,必须在同步方法快内,方法内,不能使用lock,他们调用时是锁对象.wait,要注意 此时syn(锁对象),两个所对象必须相同 ## 2,线程同步 - sync - 与wait搭配,notify搭配,若与Lock搭配会造成异常 - 多用while,不用if - 同步代码块,synchronized 自动锁 - 要求所有相乘同一把锁 synchronized(obj) obj是同一个对象,或同一个类 - 同步方法:当方法内容全部需要同步时 - 非静态方法锁即时this 需要注意 - 静态方法时,锁时当前类本身 - Lock :接口 1.5之后 - condition - 能够手动开启同步,结束同步,手动锁,指定睡眠,指定唤醒 - 实现类 - ReentrantLock:功能与synchronized,可重入锁 - ReentrantReadWriteLock.ReadLock,有读锁的线程可以共享该方法,几乎相当于没加锁 - ReentrantReadWriteLock.WriteLock,其他线程不共享该方法 - \`\`\`java ReentrantLock lock = new ReentrantLock(); final Condition flag1=lock.newCondition(); final Condition flag2=lock.newCondition(); try{ lock.lock(); flag1.await(); ... }finally{ lock.unlock(); } flag2.singal(); \`\`\` # 3,线程通信 定制化通信: \`\`\`java /\* 例: \* 切菜 \* 炒菜 \* 上菜 \* 同时10道菜 \*/ // 这里就不能用sync,需要定制化通信(唤醒睡眠的线程) // 顺序:线程 操作 资源类 Cooking Lock condation flag1,flag2,flag3 cut() cooking() gaving() Cooking new thread(()-\>{ for(int i=0;i\<5;i++) cooking.cut(); }).start() new thread(()-\>{ for(int i=0;i\<5;i++) cooking.cooking(); }).start() new thread(()-\>{ for(int i=0;i\<5;i++) cooking.giving(); }).start() \`\`\` - lambda表达式 - 接口可写静态方法实现, - 普通方法实现,加default 关键字即可 # 4,JUC工具类 数据库中读写一般不是同步的 JUC中读写都是同步的,即读写同步,因为JVM线程必须加锁,否则不安全,比数据库严格 - ReentraReadWriteLock:读写锁,写程序优先 - CountDownLatch:计数器 \`\`\`java CountDown count = new CountDown(10); count.await(); // 到此方法时会判断count里面的数值,为0时继续主线程,适用于秒杀业务 \`\`\` - CyclicBarrier:循环栅栏,多个线程处于同一状态时,才继续CyclicBarrier任务 \`\`\`java CyclicBarrier = cyc = new CyclicBarrier(7,任务) for (int i=0;i\<7;i++) new Thread(){ ()-\>{ xxxxx cyc.await(); } } \`\`\` - Semaphere:信号灯 \`\`\`java Sempahere s= new Semaphere(3); for (int i=0;i\<7;i++) new Thread(){ ()-\>{ s.acquire();// 资源不够时会阻塞 xxxx s.release();// 表示释放了资源 } } \`\`\`