多线程全面详解

线程

从软硬件实现多条执行流程的技术

多线程的创建

  1. 继承Thread类

优点:编码简单

缺点:无法继承其他类了,不利于扩展

public class Thread_1 {
    //3.创建线程对象
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();//直接调用run方法会被当成普通方法执行,调用start方法才是启动一个新的的线程
        //主线程,要把子线程任务放到主线程之前,否则就是单线程了
        for (int i = 0; i < 3; i++) {
            System.out.println("主线程"+i);
        }
    }
}
//1.继承Thread类
class MyThread extends Thread {
    //2.重写run方法
    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
            System.out.println("子线程"+i);
        }
    }
}
  1. 实现Runnable接口

优点:线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强

缺点:编程多一层对象包装,如果线程有执行结果不可以直接返回

public class Thread_2 {
    public static void main(String[] args) {
        // 2.创建MyRunnable对象
        Runnable runnable = new MyRunnable();
        // 3.把MyRunnable对象交给Thread处理
        Thread thread = new Thread(runnable);
        // 4.调用线程对象的start方法启动线程
        thread.start();

        //主线程
            for (int i = 0; i < 3; i++) {
                System.out.println("主线程"+i);
            }
    }
}
class MyRunnable implements Runnable{
    @Override
    // 1.定义一个线程任务类MyRunnable实现Runnable接口,重写run方法
    public void run() {
        for (int i = 0; i < 3; i++) {
            System.out.println("子线程"+i);
        }
    }
}

//简化版
public class Thread_2 {
    public static void main(String[] args) {

         new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 3; i++) {
                    System.out.println("子线程"+i);
                }
            }
        }).start();
         
        //主线程
            for (int i = 0; i < 3; i++) {
                System.out.println("主线程"+i);
            }
    }
}
  1. 实现Callable接口

优点:可以得到线程执行的结果

缺点:代码相对较多

public class Thread_3 {
    public static void main(String[] args) {

        Callable call = new MyCallable(100);
        //把Callable对象交给Futuretask对象,可以交给thread处理,并获得结果
        FutureTask<String> task = new FutureTask<String>(call);
        new Thread(task).start();

        //主线程
        Callable call2 = new MyCallable(200);
        FutureTask<String> task2 = new FutureTask<String>(call2);
        new Thread(task2).start();

        try {
            //通过get方法获取数据
            String s = task.get();
            System.out.println("第一个"+s);
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            String s1 = task2.get();
            System.out.println("第二个"+s1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class MyCallable implements Callable<String>{
    private int n;
    public MyCallable(int n) {
        this.n = n;
    }
    @Override
    public String call() throws Exception {
        n+=1;
        return "结果为"+n;
    }
}

线程常用方法

setName(),getName(),currentThread()

public class ThreadDemo01 {
    // main方法是由主线程负责调度的
    public static void main(String[] args) {
        Thread t1 = new MyThread("1号");
        // t1.setName("1号");
        t1.start();
        System.out.println(t1.getName());

        Thread t2 = new MyThread("2号");
        // t2.setName("2号");
        t2.start();
        System.out.println(t2.getName());

        // 哪个线程执行它,它就得到哪个线程对象(当前线程对象)
        // 主线程的名称就叫main
        Thread m = Thread.currentThread();
        System.out.println(m.getName());
        m.setName("最牛的线程");

        for (int i = 0; i < 5; i++) {
            System.out.println( m.getName() + "输出:" + i);
        }
    }
}
public class MyThread extends Thread{
    public MyThread() {
    }

    public MyThread(String name) {
        // 为当前线程对象设置名称,送给父类的有参数构造器初始化名称
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println( Thread.currentThread().getName() + "输出:" + i);
        }
    }
}

线程的休眠

public class ThreadDemo02 {
    // main方法是由主线程负责调度的
    public static void main(String[] args) throws Exception {
        for (int i = 1; i <= 5; i++) {
            System.out.println("输出:" + i);
            if(i == 3){
                // 让当前线程进入休眠状态
                // 段子:项目经理让我加上这行代码,如果用户愿意交钱,我就注释掉。
                Thread.sleep(3000);
            }
        }
    }
}

线程同步

为了解决线程安全问题,让多个线程实现先后依次访问共享资源

加锁:把共享资源上锁,每次只能一个线程进入访问,完毕以后解锁,然后其他线程才能进来

方式一:同步代码块

把出现线程安全问题的核心代码上锁,用synchronized环绕,不推荐,一把锁住了所有线程

会影响其他无关线程的执行

规范:1.建议使用共享资源作为锁对象

2.实例方法建议使用this作为锁对象

3.静态方法用字节码(类名.class)作为锁对象

synchronized (this) {
            // 2、判断余额是否足够
            if (this.money >= money) {
                // 钱够了
                System.out.println(name + "来取钱,吐出:" + money);
                // 更新余额
                this.money -= money;
                System.out.println(name + "取钱后,余额剩余:" + this.money);
            } else {
                // 3、余额不足
                System.out.println(name + "来取钱,余额不足!");
            }

方式二:同步方法

给核心方法上锁,每次只能一个线程进入方法,执行后解锁,其它线程再次进入

public synchronized void drawMoney(double money) 

方式三:同步锁

private final Lock lock = new ReentrantLock();
public void drawMoney(double money) {
        // 1、拿到是谁来取钱
        String name = Thread.currentThread().getName();
        // 2、判断余额是否足够
        // 小明  小红
        lock.lock(); // 上锁
        try {
            if(this.money >= money){
                // 钱够了
                System.out.println(name+"来取钱,吐出:" + money);
                // 更新余额
                this.money -= money;
                System.out.println(name+"取钱后,余额剩余:" + this.money);
            }else{
                // 3、余额不足
                System.out.println(name+"来取钱,余额不足!");
            }
        } finally {
            lock.unlock(); // 解锁
        }
    }

线程池

可以复用线程的技术,反复创建线程的开销会很大,会严重影响系统性能

问题:

  • 谁代表线程池?

ExecutorService接口

实现类:

  • 临时线程什么时候创建?

新任务提交时发现核心线程都在忙,任务队列也满了,并且还可以创建临时线程,此时才会创建临时线程

  • 什么时候会开始拒绝任务?

核心线程和临时线程都在忙,任务队列也满了,新的任务过来的时候才会开始任务拒绝

线程池处理Runnable任务

ExecutorService pool = new ThreadPoolExecutor(3, 5 ,6, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5) , Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy() );
       
        // 2、给任务线程池处理。
        Runnable target = new MyRunnable();
        pool.execute(target);

线程池处理Callable任务

 ExecutorService pool = new ThreadPoolExecutor(3, 5 ,6, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5) , Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy() );

        // 2、给任务线程池处理。
        Future<String> f1 = pool.submit(new MyCallable(100));
        System.out.println(f1.get());

Executors得到线程池对象的常用方法

定时器

方式一:Timer定时器

Timer timer = new Timer();  // 定时器本身就是一个单线程。
        // 2、调用方法,处理定时任务
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行AAA~~~" + new Date());
            }
        }, 0, 2000);

方式二:ScheduledExecutorServiced定时器

 // 1、创建ScheduledExecutorService线程池,做定时器
        ScheduledExecutorService pool = Executors.newScheduledThreadPool(3);

        // 2、开启定时任务
        pool.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行输出:AAA  ==》 " + new Date());

并发:CPU分时轮询的执行线程

并行:同一时刻同时在执行

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android 多线程可以通过使用AsyncTask类或Handler类来实现。引用\[1\]中提到了AsyncTask类的使用方法。AsyncTask是一个封装好的线程池,可以方便地在后台执行任务,并在主线程更新UI。在AsyncTask中,需要在主线程中创建实例,并在主线程中调用execute()方法来执行任务。每个AsyncTask实例只能执行一次execute(),如果需要执行多次,则需要创建多个实例。在AsyncTask的子类中,需要重写doInBackground()方法来执行后台任务,可以通过isCancelled()方法来判断任务是否被取消。当任务被取消时,会回调onCanceled(obj)方法,而不会调用onPostExecute()方法。引用\[2\]中提到了使用Handler类来实现多线程。可以在主线程中创建Handler实例,并在工作线程中使用Handler.post()方法发送消息到消息队列中,然后在Handler的回调方法中指定操作UI内容。通过这种方式,可以在工作线程中更新UI。需要注意的是,Handler只能在主线程中创建,并且需要在工作线程中开启Handler。以上是Android中实现多线程的两种常用方法。 #### 引用[.reference_title] - *1* *3* [Android开发中四种常用的多线程实现方式](https://blog.csdn.net/star_nwe/article/details/130140238)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [全面详解Android实现多线程的几种方式(史上最全,最详细)](https://blog.csdn.net/fubrty/article/details/124689121)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值