Java多线程

多线程总结:
进行多线程编程时,尽量使用让线程通过监控变量的方式,进行自我状态的控制

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<Future<Integer>> resultList = new ArrayList<Future<Integer>>();

        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<resultList.size();i++){
                Future<Integer> 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()<resultList.size());

        int total = 0;
        for (int i = 0;i<resultList.size();i++){
            Future<Integer> 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<studentCount;i++){
            students[i] = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        long walkTime = (long) (Math.random()*1000);
                        Thread.sleep(walkTime);
                        useLock.tryToBuyMilk();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            students[i].start();
        }
    }

}

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<workerCount;i++){
            worker[i] = new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true) {
                        try {
                            writeReadLock.viewOder();
                            long walkTime = (long) (Math.random() * 5000);
                            Thread.sleep(walkTime);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
            worker[i].start();
        }
    }

}

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<carCount;i++){
            car[i] = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        long randomTime = (long) (Math.random() * 1000);
                        Thread.sleep(randomTime);
                        if (useSemaphore.parking()) {
                            long parkingTime = (long) (Math.random() * 1300);
                            Thread.sleep(parkingTime);
                            useSemaphore.leaving();
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            car[i].start();
        }
        for (int i = 0;i < carCount;i++){
            car[i].join();
        }
    }

}

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 <runnerCount;i++){
            new Thread(new Worker(startSignal,doneSignal)).start();
        }

        System.out.println("准备工作...");
        System.out.println("准备工作就绪");
        System.out.println("比赛开始");
        startSignal.countDown();//这里变为0,43行不在等待
        doneSignal.await();//45行一直在做减一操作,latch变为0之后
        System.out.println("比赛结束");
    }


    static class Worker implements Runnable{

        private CountDownLatch startSignal;
        private CountDownLatch doneSignal;

        public Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
            this.startSignal = startSignal;
            this.doneSignal = doneSignal;
        }

        @Override
        public void run() {
            try {
                startSignal.await();
                doWork();
                doneSignal.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

            void doWork(){
            System.out.println(Thread.currentThread().getName()+": 跑完全程");
        }
    }

}

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 <studentNum;i++){
            new Thread(new Student(phaser)).start();
        }
    }
}

class Student implements Runnable{

    private Phaser phaser;

    public Student(Phaser phaser) {
        this.phaser = phaser;
    }

    @Override
    public void run() {
        try {
            doTest(1);
            phaser.arriveAndAwaitAdvance();//等到5个线程都到了,才放行
            doTest(2);
            phaser.arriveAndAwaitAdvance();
            doTest(3);
            phaser.arriveAndAwaitAdvance();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    void doTest(int i) throws InterruptedException {
        System.out.println(Thread.currentThread().getName()+"开始答第"+i+"题");
        long spendTime = (long) (Math.random()*1000);
        Thread.sleep(spendTime);
        System.out.println(Thread.currentThread().getName()+"第"+i+"道题答题结束");
    }
}

Exchanger
允许在并发线程中互相交换消息
允许在2个线程中定义同步点,当两个线程都到达同步点,他们交换数据结构
实现类:Exchanger
-exchanger,线程双发互相交换数据
-交换数据是双向的
做不到点对点的发送消息

public class UseExchanger {

    public static void main(String[] args) throws InterruptedException {

        Exchanger<String> exchanger = new Exchanger<String>();
        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<String> exchanger;

    public BackGroundWorker(Exchanger<String> 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包
<dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.3.0</version>
        </dependency>

完整代码:

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);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值