Java进阶(1)之 并发/多线程(1)

一、基础知识

进程(Pocess)和线程(Thread) 

 

1.为什么要使用多线程?

先总体上:

  • 从计算机底层来说:线程可以比作是轻量级的进程,是程序执行的最小单元,线程间的切换和调度的成本远远小于进程。另外,多核 CPU 时代意味着多个线程可以同时运行,这减少了线程上下文切换的开销。
  • 从当代互联网发展趋势来说:现在的系统动不动就要求百万级甚至千万级的并发量,而多线程并发编程正式开发高并发系统的基础,利用好多线程机制可以大大提高系统的并发能力以及性能。

再深入到计算机底层:

  • 单核时代:在单核时代多线程主要是为了提高 CPU 和 IO 设备的综合利用率。
  • 多核时代:多核时代主要是为了提高 CPU 的利用率。

2.使用多线程可能会带来什么问题?

并发编程的目的就是为了能提高程序的执行效率提高程序运行速度,但是并发编程并不总是能提高程序运行速度的,而并发编程可能会遇到很多问题,比如:内存泄漏、上下文切换、死锁等,还有受限于硬件和软件和资源闲置问题。

二、创建线程的方式

1. Thread

 Thread实现多线程url地址下载文件

首先下载一个commons-io的jar包

 

//实现多线程下载文件
public class Thread01 extends Thread{

    private String url;
    private String filename;

    public Thread01(String url, String filename) {
        this.url = url;//文件地址
        this.filename = filename;//文件保存的名字
    }
    //下载文件线程的执行体
    @Override
    public void run() {
        WebDownLoader webDownLoader = new WebDownLoader();
        webDownLoader.downloader(url,filename);
        System.out.println("下载了"+filename);
    }

    public static void main(String[] args) {
        Thread01 t1 = new Thread01("https://googleads.g.doubleclick.net/pagead/html/r20200707/r20190131/zrt_lookup.html#","1.html");
        t1.start();
        Thread01 t2 = new Thread01("https://res.wx.qq.com/a/wx_fed/assets/res/OTE0YTAw.png","2.png");
        t2.start();
        Thread01 t3 = new Thread01("https://res.wx.qq.com/a/wx_fed/assets/res/OTE0YTAw.png","3.png");
        t3.start();
    }
}
//下载文件的类
class WebDownLoader{
    //下载文件的方法
    public void downloader(String url,String filename){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(filename));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IO异常!");
        }
    }
}

2.Runnable 

3.实现Callable接口

public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable01 c1 = new Callable01("https://res.wx.qq.com/a/wx_fed/assets/res/OTE0YTAw.png", "1.png");
        Callable01 c2 = new Callable01("https://res.wx.qq.com/a/wx_fed/assets/res/OTE0YTAw.png", "2.png");
        Callable01 c3 = new Callable01("https://res.wx.qq.com/a/wx_fed/assets/res/OTE0YTAw.png", "3.png");

        //创建执行服务
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        //提交执行
        Future<Boolean> f1 = executorService.submit(c1);
        Future<Boolean> f2 = executorService.submit(c2);
        Future<Boolean> f3 = executorService.submit(c3);
        //获取结果
        Boolean b1 = f1.get();
        Boolean b2 = f2.get();
        Boolean b3 = f3.get();
        //关闭服务
        executorService.shutdownNow();
    }

三、并发问题

并发和并行有什么区别?

  • 并发:同一时间段,多个任务都在执行(单位时间内不一定同时执行);
  • 并行:单位时间内,多个任务同时执行。

并发的关键是你有处理多个任务的能力,不一定要同时。 而并行的关键是你有同时处理多个任务的能力。

龟兔赛跑问题

//模拟龟兔赛跑并发问题
public class Runnable01 implements Runnable{

    private String winner;
    @Override
    public void run() {

        for (int i=0;i<=100;i++){
            //模拟兔子休息
            if(Thread.currentThread().getName().equals("兔子") && i%10==0){
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //判断比赛是否结束
            boolean flag = gameOver(i);
            if (flag){
                break;
            }
            System.out.println(Thread.currentThread().getName()+"-->跑了"+i+"步");

        }
    }
    //判断是是否完成比赛
    private boolean gameOver(int steps){
        //判断是否有获胜者
        if (winner != null){
            return true;
        }{if(steps == 100) {//100步获胜
            winner = Thread.currentThread().getName();
            System.out.println("获胜者是**" + winner + "**");
            return true;
            }
        }
        return false;
    }

    public static void main(String[] args) {
        Runnable runnable = new Runnable01();
        new Thread(runnable,"兔子").start();
        new Thread(runnable,"乌龟").start();

    }
}

四、线程

停止线程的方式 

线程睡眠

public class Time {

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

        tenDown();
        time();
    }
    //模拟倒计时
    static void tenDown(){
        int num=10;
        while(true){
            System.out.println(num);
            num--;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (num <= 0){
                break;
            }
        }
    }
    //获取当前时间,每秒刷新一次
    static  void time() throws InterruptedException {
        while(true){
            //获取当前时间
            Date date = new Date(System.currentTimeMillis());
            System.out.println(new SimpleDateFormat("YYYY/MM/dd HH:mm:ss").format(date));
            Thread.sleep(1000);
        }
    }
}

 

线程礼让(yield)

线程强制执行(join)

线程状态观测(State)

public class Thread02 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(()->{
            //睡5秒
            for (int i=0;i<5;i++){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("线程结束!");
        });
        //观察启动前状态
        Thread.State state = thread.getState();
        System.out.println("现在的状态是:"+state);//NEW
        //观察启动后状态
        thread.start();
        state = thread.getState();
        System.out.println("现在的状态是:"+state);//RUNNABLE
        //只要
        while (state != Thread.State.TERMINATED){
            Thread.sleep(100);
            state = thread.getState();
            System.out.println(state);//TIMED_WAITING
        }

    }
}

线程优先级(Priority)

public class Priority {

    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
        Mypriorrity mypriorrity = new Mypriorrity();
        Thread t1 =new Thread(mypriorrity,"t1");
        Thread t2 =new Thread(mypriorrity,"t2");
        Thread t3 =new Thread(mypriorrity,"t3");
        Thread t4 =new Thread(mypriorrity,"t4");
        //不设置优先级,默认是5
        t1.start();
        //设置优先级
        t2.setPriority(1);
        t2.start();
        t3.setPriority(10);
        t3.start();
        t4.setPriority(7);
        t4.start();
    }
}
class Mypriorrity implements Runnable{

    @Override
    public void run() {
        //打印 线程名字-->线程优先级
        System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
    }
}

守护线程(daemon)

//守护线程
public class Daemon {
    public static void main(String[] args) {
        Thread god = new Thread(new god());
        god.setDaemon(true);//默认是false,默认是守护线程
        god.start();
        Thread person = new Thread(new person());
        person.start();
    }
}

//神
class god implements Runnable{
    @Override
    public void run() {
        while (true){
            System.out.println("神与你同在!");
        }
    }
}
//人
class person implements Runnable{
    @Override
    public void run() {
        //人生不过三万天
        for (int i=0;i<=30000;i++){
            System.out.println("===还活着===");
        }
        System.out.println("-------------GoodBye,World!----------------");
    }
}

不安全线程问题

//不安全的取钱
public class UnSafeBank {
    public static void main(String[] args) {
        Account account = new Account("学习基金",100);
        Bank take1 = new Bank(account,50,"沈云飞1");
        Bank take2 = new Bank(account,100,"沈云飞2");
        new Thread(take1,"沈云飞").start();
        new Thread(take2,"syf").start();
    }
}
//用户
class Account{
    String name;
    int money;
    public Account(String name,int money){
        this.money=money;
        this.name=name;
    }
}
//银行 模拟取钱
class Bank implements Runnable{
    Account account;//账户
    int takeMoney;//取多少钱
    int lastMoney;//手里有多少钱

    public Bank(Account account, int takeMoney, String name) {
        this.account = account;
        this.takeMoney = takeMoney;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if(account.money - takeMoney < 0){
            System.out.println(Thread.currentThread().getName()+" 的余额不足!");
        }
        System.out.println("您的账户有"+account.money+"万刀");
        //卡内余额
        account.money = account.money - takeMoney;
        //取到的钱
        lastMoney = lastMoney + takeMoney;
        System.out.println(Thread.currentThread().getName()+" 您取到的钱为:"+lastMoney);
        System.out.println(Thread.currentThread().getName()+" 卡内余额为:"+account.money);

    }
}

线程同步

改良上边的方法加个同步块

 死锁

他们会互相强占对方拥有的资源,无法进行自己后边的操作 

解决办法,把自己第二个锁从第一个锁里拿出来就行了.

Lock锁

public class Lock {

    public static void main(String[] args) {
        Tricket tricket = new Tricket();
        new Thread(tricket).start();
        new Thread(tricket).start();
        new Thread(tricket).start();
    }
}
class Tricket implements  Runnable{
    int num = 9;
    //定义Lock锁
    private ReentrantLock lock = new ReentrantLock();
    @Override
    public void run() {
        while (true){
            try {
                lock.lock();//加锁
                if(num>0){
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(num);
                    num--;
                }else  break;
            }finally {
                lock.unlock();//解锁
            }

        }
    }
}

synchronized 和 Lock 的对比

线程池

1.Runnable 

//Runnable接口线程池
public class Pool {
    public static void main(String[] args) {
        //1.创建服务
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        //2.启动
        executorService.submit(new MyThread());
        executorService.submit(new MyThread());
        executorService.submit(new MyThread());
        executorService.submit(new MyThread());
        //3.关闭
        executorService.shutdownNow();
    }
}
class MyThread implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

因为Executors.newFixedThreadPool(3); 所以最大线程只是3个

2.Callable

//Callable接口线程池
public class Pool02 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //执行服务
        ExecutorService executorService = Executors.newFixedThreadPool(4);
        //提交执行
        Future submit = executorService.submit(new MyThread01());
        Future submit2 = executorService.submit(new MyThread01());
        Future submit3 = executorService.submit(new MyThread01());
        Future submit4 = executorService.submit(new MyThread01());
        //获取结果
        Object o = submit.get();
        //关闭服务
        executorService.shutdownNow();


    }
}
class MyThread01 implements Callable {

    @Override
    public Object call() throws Exception {
        System.out.println(Thread.currentThread().getName());
        return null;
    }
}

 

weixin028基于微信小程序小说阅读器设计+ssm后端毕业源码案例设计 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值