多线程总结:
进行多线程编程时,尽量使用让线程通过监控变量的方式,进行自我状态的控制
public class Thread7 {
public static void main(String[] args) throws InterruptedException {
Thread t71 = new Thread(new Thread71());
Thread72 thread72 = new Thread72();
Thread t72 = new Thread(thread72);
t71.start();
t72.start();
TimeUnit.SECONDS.sleep(2);
t71.interrupt();
thread72.flag = false;
System.out.println("main thread is exiting");
}
}
class Thread71 implements Runnable{
public void run() {
while (!interrupted()){
System.out.println("test Threa71 is running");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
}
}
class Thread72 implements Runnable{
public volatile boolean flag = true;
public void run() {
while (flag){
System.out.println("test Thrad72 is running");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
}
}
多线程死锁:
哲学家进餐问题
预防死锁,对资源进行等级排序(这里就是指规定下面的线程必须按照先拿r1,再拿r2)
守护线程(后台)
线程睡眠的方法:
Thread.sleep(毫秒)
TimeUnit.SECONDS.sleep(秒)
public class Thread5 {
public static Integer r1 = 1;
public static Integer r2 = 2;
public static void main(String[] args) {
Thread51 thread51 = new Thread51();
thread51.start();
Thread52 thread52 = new Thread52();
thread52.start();
}
}
class Thread51 extends Thread{
@Override
public void run() {
synchronized (Thread5.r1){
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (Thread5.r2){
System.out.println("Thread51 have finish");
}
}
}
}
class Thread52 extends Thread{
@Override
public void run() {
synchronized (Thread5.r2){
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (Thread5.r1){
System.out.println("Thread52 have finish");
}
}
}
}
守护线程:
普通线程的结束,是run方法运行结束
守护线程的结束,是run方法运行结束,或main函数结束
守护线程永远不要访问资源,如文件或数据库等,因为main函数一旦结束,它也会强制的结束,他来不及释放在这些资源
public class Thread6 {
public static void main(String[] args) throws InterruptedException {
Thread testThread = new Thread(new TestThread4());
testThread.setDaemon(true);
testThread.start();
TimeUnit.SECONDS.sleep(2);
System.out.println("main thread is exiting");
}
}
class TestThread4 implements Runnable{
public void run() {
while (true){
System.out.println("I am Running");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Java并发框架Executor:
业务:任务多,数据量大
串行vs并行
并行困难(任务分配和执行过程高度耦合)
如何控制粒度,切割任务
如何分配任务给线程,监督线程的执行过程
主从模式:(Master-Slave)
Worker模式:(worker-worker)
Java并发编程
Thread/runnable/Thread组管理
Executor(本节重点)
Fork-Join框架
线程组ThreadGroup
线程集合
树形结构,大线程组可以包括小线程
Executors并发框架:
Executors.newFixedThreadPool(n);//创建n个线程
Executors.newCachedThreadPool();//动态创建线程,线程数动态增加
通过实现Callable接口,并用Future可以来接收多线程的执行结果。
public class SumTask implements Callable {
private Integer startNum;
private Integer endNum;
public SumTask(Integer startNum, Integer endNum) {
this.startNum = startNum;
this.endNum = endNum;
}
public Integer call() {
Integer sum = 0;
for (int i =startNum;i<=endNum;i++){
sum += i;
}
try {
// TimeUnit.SECONDS.sleep(new Random().nextInt(1));
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("%s: %d\n",Thread.currentThread().getName(),sum);
return sum;
}
}
用四个线程执行计算1-1000之间所有数字的总和:
public class SumTest {
public static void main(String[] args) {
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(4);
ArrayList> resultList = new ArrayList>();
for (int i = 0;i<10;i++){
SumTask calculator = new SumTask(i*100+1,(i+1)*100);
Future result = executor.submit(calculator);
resultList.add(result);
}
do {
System.out.printf("Main:已经完成了多少个的任务: %d\n",executor.getCompletedTaskCount());
for (int i = 0;i result = resultList.get(i);
System.out.printf("Main: Task %d: %s\n",i,result.isDone());
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}while (executor.getCompletedTaskCount() result = resultList.get(i);
Integer sum = null;
try {
sum = result.get();
total += sum;
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
System.out.println("1-1000的总和:"+total);
executor.shutdown();
}
}
任务创建和执行过程耦合问题
1.以前创建线程时,是在run方法中执行任务
2.使用Executors后,可以使用executor.execute(task),可以有效多线程执行效率
Fork-Join框架
Java7提供另一种并行框架:分解,治理,合并(分治编程)
适合整体任务量不好确定的场合(最小任务可确定)
Thread/EXecutor/Fork-join
线程之间发生了什么是看不到的,线程之间缺少协作的
synchronized同步
简单粗暴,性能损失有点大
Lock:
实现更复杂的临界区
tryLock方法可以判断锁是否空闲
允许读写分离的操作,多个读,一个写,读是共享的,写是排他的
性能更好
ReentrantLock类,可重入的互斥锁
ReentrantReadWriteLock类,可重入的读写锁
lock和unlock函数
private final static ReentrantLock REENTRANT_LOCK = new ReentrantLock();
//可重入锁的使用
排队买奶茶案例:
public class UseLock {
private final static ReentrantLock REENTRANT_LOCK = new ReentrantLock();//可重入锁
public static void main(String[] args) {
buyMilk();
}
public void tryToBuyMilk(){
boolean flag = true;
while (flag){
if (REENTRANT_LOCK.tryLock()){
try {
long waitTime = (long) (Math.random()*500);
Thread.sleep(waitTime);
System.out.println("来一杯珍珠奶茶,不要珍珠");
flag = false;
REENTRANT_LOCK.unlock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
System.out.println(Thread.currentThread().getName()+": 再等等");
}
if (flag){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void buyMilk(){
final UseLock useLock = new UseLock();
int studentCount = 10;
Thread[] students = new Thread[studentCount];
for (int i = 0;i
private final static ReentrantReadWriteLock READ_WRITE_LOCK = new ReentrantReadWriteLock();
可重入读写锁的使用:
public class WriteReadLock {
public static void main(String[] args) {
handleOder();
}
private final static ReentrantReadWriteLock READ_WRITE_LOCK = new ReentrantReadWriteLock();
public void viewOder() throws InterruptedException {
READ_WRITE_LOCK.readLock().lock();
long viewTime = (long) (Math.random()*500);
Thread.sleep(viewTime);
System.out.println(Thread.currentThread().getName()+"查看订单");
READ_WRITE_LOCK.readLock().unlock();
}
public void writeOder() throws InterruptedException {
READ_WRITE_LOCK.writeLock().lock();
long writeTime = (long) (Math.random()*1000);
Thread.sleep(writeTime);
System.out.println("老板新添加一笔订单");
READ_WRITE_LOCK.writeLock().unlock();
}
public static void handleOder(){
final WriteReadLock writeReadLock = new WriteReadLock();
Thread boss = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
writeReadLock.writeOder();
long waitingTime = (long) (Math.random() * 1000);
Thread.sleep(waitingTime);
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
}
}
});
boss.start();
int workerCount = 3;
Thread[] worker = new Thread[workerCount];
for (int i = 0;i
semaphore:可以限制线程的访问量,设置多个并发量,本质上是一个计数器
Semaphore:
tryacquire:尝试获取
acquire获取
release释放
比lock更进一步,可以控制多个同时访问的关键区
public class UseSemaphore {
private final static Semaphore SEMAPHORE = new Semaphore(5);
public boolean parking(){
if (SEMAPHORE.tryAcquire()){
System.out.println(Thread.currentThread().getName()+" :停车成功");
return true;
}else {
System.out.println(Thread.currentThread().getName()+": 没有空位");
return false;
}
}
public void leaving(){
SEMAPHORE.release();
System.out.println(Thread.currentThread().getName()+" : 开走了");
}
public static void main(String[] args) throws InterruptedException {
int carCount = 10;
final UseSemaphore useSemaphore = new UseSemaphore();
Thread[] car = new Thread[carCount];
for (int i =0;i
Latch :门上的插销
用来等待所有线程都到然后一起执行
等待锁,是一个同步辅助类
实现类:CountDownLatch
构造函数可以传入需要同步的线程数量
countDown()计数减1;
await() 等待latch变成0;只有latch变为0,await就会停止等待,所有线程开始执行
设想百米赛跑比赛 发令枪发出信号后选手开始跑,全部选手跑到终点后比赛结束
public class UseCountDownLatch {
public static void main(String[] args) throws InterruptedException {
int runnerCount = 10;
CountDownLatch startSignal = new CountDownLatch(1);
CountDownLatch doneSignal = new CountDownLatch(runnerCount);
for (int i = 0;i
Barrier:
集合点,也是一个同步辅助类
允许线程在莫一个点上进行同步
实现类:CyclicBarrier
构造函数是需要同步线程数量,和回调动作的方法
await等待其他线程,到达数量后就放行
当在Barrier上await的线程数量达到预定要求后,所有的await的线程不在等待,全部解锁。并且,Barrier将执行预定的回调动作(在本程序中,回调动作就是CalculateFinalResult)
假定有三行数,用三个线程分别计算每一行的和,最终计算总和
public class UseCyclicBarrier {
public static void main(String[] args) {
int [][] numbers = new int[3][5];
int [] result = new int[3];
int [] row1 = new int[]{1,2,3,4,5};
int [] row2 = new int[]{6,7,8,9,10};
int [] row3 = new int[]{10,20,30,40,50};
numbers[0] = row1;
numbers[1] = row2;
numbers[2] = row3;
CalculateFinalResult finalResultCalculator = new CalculateFinalResult(result);
CyclicBarrier barrier = new CyclicBarrier(3, finalResultCalculator);
//需要三个线程执行barrier.await(),才会执行后面的finalResultCalculator,所以下面的for循环先执行
for (int i = 0;i < 3;i++){
CalculateEachRow calculateEachRow = new CalculateEachRow(numbers, i, result, barrier);
new Thread(calculateEachRow).start();
}
}
}
class CalculateEachRow implements Runnable{
int [][] numbers;
int rowNumber;
int [] result;
CyclicBarrier barrier;
public CalculateEachRow(int[][] numbers, int rowNumber, int[] result, CyclicBarrier barrier) {
this.numbers = numbers;
this.rowNumber = rowNumber;
this.result = result;
this.barrier = barrier;
}
@Override
public void run() {
int sum = 0;
int [] rowNum = numbers[rowNumber];
for (int data : rowNum) {
sum += data;
}
result[rowNumber] = sum;
System.out.printf("%s: 计算第%d行结束,结果为:%d\n",Thread.currentThread().getName(),rowNumber+1,sum);
try {
barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
class CalculateFinalResult implements Runnable{
int [] eachRowResult;
int finalResult;
public CalculateFinalResult(int[] eachRowResult) {
this.eachRowResult = eachRowResult;
}
public int getFinalResult() {
return finalResult;
}
@Override
public void run() {
for (int data : eachRowResult) {
finalResult += data;
}
System.out.println("最终结果为:"+finalResult);
}
}
Phaser:
允许执行并发多阶段任务,同步辅助类
在每一个阶段结束的位置对线程进行同步,当所有的线程都到达这步,再进行下一步
实现类:Phaser
-arrive //经过这个线程的,可以不等待其他线程
-arriveAndAwaitAdvance() //等待其他线程全部到达,在执行
假设举行考试,总共三道大题,每次下发一道题目,等所有学生完成后再进行下一道
public class UsePhaser {
public static void main(String[] args) {
int studentNum = 5;
Phaser phaser = new Phaser(studentNum);
for (int i = 0;i
Exchanger
允许在并发线程中互相交换消息
允许在2个线程中定义同步点,当两个线程都到达同步点,他们交换数据结构
实现类:Exchanger
-exchanger,线程双发互相交换数据
-交换数据是双向的
做不到点对点的发送消息
public class UseExchanger {
public static void main(String[] args) throws InterruptedException {
Exchanger exchanger = new Exchanger();
new Thread(new BackGroundWorker(exchanger)).start();
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.println("输入要查询的属性学生姓名:");
String inpVal = scanner.nextLine().trim();
exchanger.exchange(inpVal);//与47行交换数据
String value = exchanger.exchange(null);//与50,53等行交换数据
if ("exit".equals(value)){
break;
}
System.out.println("查询结果:"+value);
}
scanner.close();
}
}
class BackGroundWorker implements Runnable{
private Exchanger exchanger;
public BackGroundWorker(Exchanger exchanger) {
this.exchanger = exchanger;
}
@Override
public void run() {
while (true){
try {
String item = exchanger.exchange(null);
switch (item){
case "zhangsan":
exchanger.exchange("90");
break;
case "lisi":
exchanger.exchange("80");
break;
case "wangwu":
exchanger.exchange("70");
break;
case "exit":
exchanger.exchange("exit");
return;
default:
exchanger.exchange("查无此人");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
java.util.concurrent包提供了很多并发编程的控制类
根据业务特点,使用正确的线程并发控制
定时任务:
-固定某一个时间运行
-以某一个周期
简单定时器:
Timer类 定时器 :管理成本比较大
TimerTask封装任务
TimerTask继承自runnable接口
Executor+定时器机制
实现类:ScheduleExecutorService
ScheduledExecutorService executor = Executors.newScheduledThreadPool(n);
executor.schedule(Task,周期时间长度,单位)
以上一个任务开始的时间计时
executor.scheduleAtFixedRate(Task,延迟时间长度,周期时间长度,单位)
以上一个任务结束时开始计时
executor.scheduleWithFixedDelay(Task,延迟时间长度,周期时间长度,单位)
-定时任务
-周期任务
public class UseExecutorScheduled {
public static void main(String[] args) throws InterruptedException {
// executorSchedule();
// executorScheduleAtFixedRate();//3秒
executorScheduleWithFixedDelay();//4秒
}
public static void executorSchedule() throws InterruptedException {
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
executorService.schedule(
new MyTask(),
1,
TimeUnit.SECONDS);
Thread.sleep(20000);
executorService.shutdown();
}
public static void executorScheduleAtFixedRate() throws InterruptedException {
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
executorService.scheduleAtFixedRate(
new MyTask(),
1,
3000,
TimeUnit.MILLISECONDS);
Thread.sleep(20000);
executorService.shutdown();
}
public static void executorScheduleWithFixedDelay() throws InterruptedException {
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
executorService.scheduleWithFixedDelay(
new MyTask(),
1,
3000,
TimeUnit.MILLISECONDS);
Thread.sleep(20000);
executorService.shutdown();
}
}
class MyTask implements Runnable{
@Override
public void run() {
System.out.println("时间为:"+new Date());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Quartz:
-Quartz
1.创建一个scheduler
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
2.定义一个Trigger,Trigger相当于一个规则
3.定义一个Job
4.加入这个调度
scheduler.scheduleJob(job, trigger);
5.启动
scheduler.start();
6.运行一段时间后关闭
Thread.sleep(10000);
scheduler.shutdown(true);
定义任务(Job):
import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.util.Date;
public class HelloJob implements Job {
public void execute(JobExecutionContext context) throws JobExecutionException {
JobDetail detail = context.getJobDetail();
String name = detail.getJobDataMap().getString("name");
System.out.println("hello from " + name + " at " + new Date());
}
}
//定义一个JobDetail
JobDetail job = newJob(HelloJob.class) //定义Job类为HelloQuartz类
.withIdentity("job1", "group1") //定义name/group
.usingJobData("name", "quartz") //定义属性
.build();
引入jar包
org.quartz-scheduler
quartz
2.3.0
完整代码:
import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.util.Date;
/**
* @author lixiang1234_李祥
* @site www.lixiang.com
* @create 2020-04-05 16:30
*/
public class DefaultJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
JobDetail jobDetail = jobExecutionContext.getJobDetail();
String name = jobDetail.getJobDataMap().getString("name");
System.out.println("hello from "+name+" at "+new Date());
}
}
public class UseQuartz {
public static void main(String[] args) throws SchedulerException, InterruptedException {
//1.创建scheduler
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
//2.定义一个Trigger
Trigger trigger = newTrigger().withIdentity("trigger1", "group1") //定义name/group
.startNow()//一旦加入scheduler,立即生效
.withSchedule(simpleSchedule() //使用SimpleTrigger
.withIntervalInSeconds(2) //每隔2秒执行一次
.repeatForever()) //一直执行
.build();
//3.定义一个JobDetail
JobDetail job = newJob(HelloJob.class) //定义Job类为HelloQuartz类
.withIdentity("job1", "group1") //定义name/group
.usingJobData("name", "quartz") //定义属性
.build();
//4.加入这个调度
scheduler.scheduleJob(job,trigger);
//5.启动
scheduler.start();
//6.关闭
Thread.sleep(12000);
scheduler.shutdown(true);
}
}