Java多线程,Android多线程

2023-11-11

目录

一、线程的概念

二、线程创建的方式及特点

三、线程创建方式

1、继承Thread类

2、实现Runnable接口

3、实现Callable接口(我觉得了解即可)

4、AsyncTask异步任务(被弃用)

5、AsyncTask替代方案

四、线程的基础操作

1、线程停止---true/false

2、线程休眠---sleep()

3、线程礼让---yield()

4、线程插队---join()

5、 线程优先级---setPriority(int p)

6、 线程状态---isAlive()

五、守护线程

六、线程同步

1、线程同步的概念

2、synchronized

3、Lock

3.1、为什么使用lock会出现只有一个线程拿到锁?

 七、线程通信

1、线程通信的方法

3、Android-handler通信

3.1、handler的通信机制

3.2、handler常用的基础send方法

3.3、handler常用的高级post方法 

 八、线程的六个状态

1、验证new,runnable,terminated状态

2、验证blocked状态

3、验证waiting状态

4、验证timed_waiting状态

九、线程池

1、线程池的优点

2、线程池类型

2.1、newCachedThreadPool

2.2、newFixedThreadPool

2.3、newSingleThreadExecutor

十、死锁


一、线程的概念

  • 线程是操作系统能够进行运算调度的最小单位;
  • 一个进程中可以并发多个线程,每条线程并行执行不同的任务;
  • 很多多线程都是模拟出来的,真正的多线程是指有多个cpu,即多核,如服务器,如果是模拟出来的多线程,即在一个cpu的情况下,在同一个时间点,cpu只能执行一个代码,因为切换的很快,所以就有同时执行的错觉。

二、线程创建的方式及特点

创建方式 特点
继承Thread java中是单继承,具有局限性
实现Runnable接口 灵活,方便同一个对象被多个线程使用
实现Callable接口

Callable接口要重写的call()方法是可以有返回值的。

call()方法可以抛出异常,供外部捕获。

Callable接口支持泛型。

AsyncTask api 30(Android 11)中AsyncTask被正式废弃

三、线程创建方式

1、继承Thread类

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        MyThread myThread=new MyThread();
        myThread.start();
    }


    class MyThread extends Thread{
        @Override
        public void run() {
            Log.e("sjd====","开启子线程");
        }
    }

  当然,如果只是简单的开启子线程,也可直接使用匿名类开启

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        new Thread(){
            @Override
            public void run() {
                Log.e("sjd====","开启子线程");
            }
        }.start();
    }

2、实现Runnable接口

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        MyThread myThread=new MyThread();
        Thread thread=new Thread(myThread);
        thread.start();
    }


    class MyThread implements Runnable{
        @Override
        public void run() {
            Log.e("sjd====","开启子线程");
        }
    }

  当然,如果只是简单的开启子线程,也可直接使用匿名类开启 

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Runnable runnable=new Runnable(){
            @Override
            public void run() {
                Log.e("sjd====","开启子线程");
            }
        };
        Thread thread=new Thread(runnable);
        thread.start();
    }

3、实现Callable接口(我觉得了解即可)

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        MyThread myThread = new MyThread();
        FutureTask futureTask = new FutureTask(myThread);
        new Thread(futureTask).start();
    }


    class MyThread implements Callable<Integer> {
        @Override
        public Integer call() throws Exception {
            Log.e("sjd====","开启子线程");
            return null;
        }
    }

4、AsyncTask异步任务(被弃用

onPreExecute 主线程中调用,任务开始前调用,可以做一些初始化操作,例如显示进度条
doInBackground 子线程中运行的方法,执行耗时任务,可以调用publishProgress方法来反馈执行进度
onProgressUpdate publishProgress调用之后,会调用onProgressUpdate
onPostExecute 切换到主线程中执行的方法,更新UI

5、AsyncTask替代方案

  • 使用 Executors 线程池替代,具体案例查看下面线程池的使用。

四、线程的基础操作

1、线程停止---true/false

  • JDK推荐的stop()和destroy()已被弃用,我们可以自己设置标志位,通过true和false的方式让线程停止,这个比较简单,这里不再写示例。

2、线程休眠---sleep()

  • 调用Thread.sleep(毫秒数),sleep时间到达时间之后,子线程又会进入到就绪状态
  • 因为在java中,每个对象都有一个锁,sleep的时候不会释放锁

3、线程礼让---yield()

  • 线程礼让,是指让当前正在执行的线程暂停,但是不阻塞,不会让出锁
  • 此时的线程从运行状态转变为就绪状态;
  • 礼让能否成功,看当前CPU如何分配调度
  • 示例:
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        MyThread myThread = new MyThread();

        Thread t1=new Thread(myThread,"子线程1");
        Thread t2=new Thread(myThread,"子线程2");

        t1.start();
        t2.start();
    }


    class MyThread implements Runnable {
        @Override
        public void run() {
            try {
                Log.e("sjd====",Thread.currentThread().getName()+"开始");
                for (int i=0;i<100;i++){
                    if (i==90){
                        Thread.yield();
                    }
                }
                Log.e("sjd====",Thread.currentThread().getName()+"结束");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }
  • 运行结果:(yiled()方法的作用是放弃当前CPU的资源,将资源让给其它线程,但放弃的时间不确定,有可能刚刚放弃,又马上获得了CPU时间片。所以下面的结果不是固定的,看CPU心情了~~~)

4、线程插队---join()

  • join合并线程,等待当前插入的线程先执行,再执行其他线程,此时其他线程是阻塞状态;
  • 示例:
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        MyThread myThread = new MyThread();

        Thread t1=new Thread(myThread,"子线程---");

        t1.start();
        for (int i=0;i<5;i++){
            if (i==1){
                try {
                    t1.join();
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            Log.e("sjd====",Thread.currentThread().getName()+"---"+i);
        }

    }
  • 运行结果:

5、 线程优先级---setPriority(int p)

  • 通过源码分析,最大为10,最小为1;
  • 按理说优先级越高的线程会优先执行,但是也不一定,看CPU调度

6、 线程状态---isAlive()

  • 查看线程的活动状态

五、守护线程

  •  线程可以分为两种,一种是用户线程,一种是守护线程
  • 守护线程必须要等所有的用户线程执行完,才会停止
  • 虚拟机必须确保用户线程执行完,不用等守护线程执行完
  • 典型的守护线程的用法就是垃圾回收线程
  • 示例:
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        MyThread myThread = new MyThread();
        MyThread2 myThread2 = new MyThread2();

        Thread t1 = new Thread(myThread);
        Thread t2 = new Thread(myThread2);
        t1.setDaemon(true);
        t1.start();
        t2.start();
    }


    class MyThread implements Runnable {
        @Override
        public void run() {
            while (true){
                Log.e("sjd====","守护线程");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
  • 运行结果:

六、线程同步

在说线程同步之前,先举个非常典型的例子,卖火车票,当同时有多个人来买票的时候,假如不做任何限制,会有什么样的情况?

示例代码:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        MyThread myThread = new MyThread();

        Thread t1 = new Thread(myThread, "用户一");
        Thread t2 = new Thread(myThread, "用户二");
        Thread t3 = new Thread(myThread, "用户三");

        t1.start();
        t2.start();
        t3.start();
    }


    class MyThread implements Runnable {
        int total = 10;//假设现在只剩下了10张火车票
        boolean isGood=true;//判断是否还有余票

        @Override
        public  void run() {
            while (isGood) {
                    //如果票数为0
                    if (total <= 0) {
                        isGood=false;
                        Log.e("sjd====", Thread.currentThread().getName() + "没有买到票");
                        return;
                    }
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    Log.e("sjd====", Thread.currentThread().getName() + "买到了第" + total + "张火车票");
                    total--;
            }
        }
    }

运行结果:(结果不唯一,多试几次)

很显然下面的运行结果是错误

这种情况下,就要用到线程同步

1、线程同步的概念

按照上面的例子进行理解,就是,当多个线程访问同一个对象,大家都在修改这个对象,造成了数据错误,这时候就需要用到线程同步,说白了,线程同步就是一种等待机制,等上一个线程操作完,再继续操作,形成一种队列的形式,避免数据错误。

2、synchronized

  • synchronized 是JVM层面的隐式锁,作用域外自动解锁,是Java关键字对象只有在同步块或同步方法中才能调用wait/notify方法
  • synchronized 不需要用户去手动释放锁,synchronized 代码执行完后系统会自动让线程释放对锁的占用
  • synchronized是不可中断类型的锁,除非加锁的代码中出现异常或正常执行完成
  • synchronzied锁的是对象,每个对象对应一把锁,每个synchronzied执行都要获取对象的锁,否则会线程阻塞,而且一旦执行,就自己独占这个对象的锁,直到执行结束,后面被阻塞的线程才能获取这个对象的锁,继续执行
  • 当两个并发线程访问同一个对象这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块
  • synchronzied的缺点就是如果修饰方法,会影响执行效率
  • synchronzie可修饰方法,也可以修饰代码块
  • sleep()需要放在同步块中,同步块中是为了多线程并发处理,按照顺序依次执行,sleep()方法就是想让当前线程进入阻塞状态,不释放锁,等到sleep()的时间到了,再进入就绪态,等待cpu调度。所以就不放在同步块中。
  • 示例代码:(把上面的代码稍作修改)
    class MyThread implements Runnable {
        int total = 10;//假设现在只剩下了10张火车票
        boolean isGood = true;//判断是否还有余票

        @Override
        public void run() {
            while (isGood) {
                synchronized (this) {

                    //如果票数为0
                    if (total <= 0) {
                        isGood = false;
                        Log.e("sjd====", Thread.currentThread().getName() + "没有买到票");
                        return;
                    }
                    Log.e("sjd====", Thread.currentThread().getName() + "买到了第" + total + "张火车票");
                    total--;
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }
    }
  • 运行结果:

3、Lock

  • lock是显示锁,显示的定义同步锁,只能修饰代码块,代码块锁
  • ReentrantLock是lock的实现类,和synchronzied有相同的作用,可以显示的进行加锁,释放锁
  • 每次只能有一个线程对lock对象加锁,线程开始访问共享资源之前应先获得lock对象
  • 示例代码:
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
    
            MyThread myThread = new MyThread();
    
            Thread t1 = new Thread(myThread, "用户一");
            Thread t2 = new Thread(myThread, "用户二");
            Thread t3 = new Thread(myThread, "用户三");
    
            t1.start();
            t2.start();
            t3.start();
    
        }
    
        class MyThread implements Runnable {
            int total = 10;//假设现在只剩下了10张火车票
            boolean isGood = true;//判断是否还有余票
    
            ReentrantLock reentrantLock=new ReentrantLock();
    
            @Override
            public void run() {
                while (isGood) {
                    reentrantLock.lock();
                    try {
                        //如果票数为0
                        if (total <= 0) {
                            isGood = false;
                            Log.e("sjd====", Thread.currentThread().getName() + "没有买到票");
                            break;
                        }
                        Log.e("sjd====", Thread.currentThread().getName() + "买到了第" + total + "张火车票");
                        total--;
                    }finally {
                        reentrantLock.unlock();
                    }
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
  • 运行结果

3.1、为什么使用lock会出现只有一个线程拿到锁?

  • 锁Lock分为“公平锁”和“非公平锁”,公平锁表示线程获取锁的顺序是按照线程加锁的顺序来分配的,即先来先得的FIFO先进先出顺序。而非公平锁就是一种获取锁的抢占机制,是随机获得锁的,和公平锁不一样的就是先来的不一定先得到锁,这个方式可能造成某些线程一直拿不到锁。

3.2、lock设置公平锁

  • ReentrantLock lock=new ReentrantLock(true);让线程排队,但是会比较消耗系统资源

3.3、lock和synchronized的比较

  • lock是显示锁,更灵活,默认是非公平锁,性能更好,扩展性更好
  • synchronized隐式锁,作用域外自动释放

 七、线程通信

1、线程通信的方法

wait() 线程挂起
notify() 唤醒线程
notifyall() 唤醒所有线程(优先级高的线程先被唤醒)
2、java中的线程通信案例

案例:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv_button = (TextView) findViewById(R.id.tv_button);
        tv_button1 = (TextView) findViewById(R.id.tv_button1);
        tv_button.setOnClickListener(this);

        MyThread myThread = new MyThread();

        Thread t1 = new Thread(myThread, "a");
        Thread t2 = new Thread(myThread, "b");

        t1.start();
        t2.start();
    }


    class MyThread implements Runnable {
        @Override
        public void run() {
            synchronized (this) {
                for (int i = 1; i <= 100; i++) {
                    Log.e("sjd====", Thread.currentThread().getName() + "---" + i);
                    if (i==10){
                        notify();
                    }
                    if (i==50){
                        try {
                            wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                notify();
            }
        }
    }

结果分析:

  1. 首先是线程同步方法中执行;
  2. 此时只有线程a,当i=10的时候,没有阻塞可唤醒的线程;
  3. a线程循环输出1-50,i=50的时候,此时调用wait被阻塞,让出锁
  4. 线程b开始执行,i=10的时候,唤醒a线程;
  5. 虽然a线程被唤醒,但是b线程未执行完,所以b线程一直循环输出1-50
  6. b线程i=50的时候,b线程阻塞,a线程开始执行输出51-100;
  7. a线程结束,让出锁,b线程继续输出51-100

3、Android-handler通信

3.1、handler的通信机制

Message

消息

Hanlder

发送和处理消息,来处理main线程和其他线程之间的通信

Looper

负责循环从消息队列取消息

MessageQueue

消息队列,先进先出

3.2、handler常用的基础send方法

  1. sendEmptyMessage(int),发送空消息
  2. sendMessage(Message),发送message
  3. sendMessageAtTime(Message,long),在确定的时间发送消息
  4. sendMessageDelayed(Message,long),发送消息,延迟
  5. 示例:
    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    
        TextView tv_button;
        TextView tv_button1;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            tv_button = (TextView) findViewById(R.id.tv_button);
            tv_button1 = (TextView) findViewById(R.id.tv_button1);
            tv_button.setOnClickListener(this);
        }
    
        Handler handler=new Handler(){
            @Override
            public void handleMessage(@NonNull Message msg) {
                super.handleMessage(msg);
                switch (msg.what){
                    case 1:
                        String str= (String) msg.obj;
                        tv_button1.setText(str);
                        break;
                }
    
            }
        };
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.tv_button:
                    Message message=new Message();
                    message.what=1;
                    message.obj="1231231";
                    handler.sendMessageAtTime(message,2000);
                    break;
            }
        }
    }

3.3、handler常用的高级post方法 

  1. post(Runnable),把子线程的Runnable对象切换到主线程队列中,等待执行
  2. postAtTime(Runnable,long)
  3. postDelayed(Runnable,long)
  4. 示例:
    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    
        TextView tv_button;
        TextView tv_button1;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            tv_button = (TextView) findViewById(R.id.tv_button);
            tv_button1 = (TextView) findViewById(R.id.tv_button1);
            tv_button.setOnClickListener(this);
        }
    
        Handler handler=new Handler(){
            @Override
            public void handleMessage(@NonNull Message msg) {
                super.handleMessage(msg);
                switch (msg.what){
                    case 1:
                        String str= (String) msg.obj;
                        tv_button1.setText(str);
                        break;
                }
    
            }
        };
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.tv_button:
                    new Thread(){
                        @Override
                        public void run() {
                            //子线程运行
                            handler.post(new Runnable() {
                                @Override
                                public void run() {
                                    tv_button1.setText("1231234123");
                                }
                            });
                        }
                    }.start();
                    break;
            }
        }
    }

 八、线程的六个状态

点到源码进行查看

new 刚开始创建,初始化
runnable

准备状态

  • ready:准备
  • running:执行
blocked 阻塞状态
waiting 等待状态,调用wait方法
timed_waiting 超时等待,等固定时间就不等了
terminated 结束状态

1、验证new,runnable,terminated状态

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        MyThread myThread = new MyThread();

        Thread t1 = new Thread(myThread, "用户一");
        Thread t2 = new Thread(myThread, "用户二");
        Thread t3 = new Thread(myThread, "用户三");
        Log.e("sjd====","-1--"+t1.getState());
        t1.start();
        Log.e("sjd====","-2--"+t1.getState());
//        t2.start();
//        t3.start();

        try {
            Thread.sleep(2000);
            Log.e("sjd====","-4--"+t1.getState());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Log.e("sjd====","-5--"+t1.getState());
    }

    class MyThread implements Runnable {
        @Override
        public void run() {
            Log.e("sjd====","-3--"+Thread.currentThread().getState());
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

2、验证blocked状态

为什么下面加1秒的延时,是同步线程的时候,当线程2调用start方法之后,可能还没有调用,还没进入到阻塞状态,所以延迟1秒

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv_button = (TextView) findViewById(R.id.tv_button);
        tv_button1 = (TextView) findViewById(R.id.tv_button1);
        tv_button.setOnClickListener(this);


        MyThread myThread = new MyThread();

        Thread t1 = new Thread(myThread, "用户一");
        Thread t2 = new Thread(myThread, "用户二");
        t1.start();
        t2.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Log.e("sjd====1", "---" + t2.getName() + " " + t2.getState());

    }

    class MyThread implements Runnable {
        @Override
        public void run() {
            synchronized (this) {
                for (int i = 0; i < 10; i++) {
                    Log.e("sjd====", "---" + Thread.currentThread().getName() + " " + Thread.currentThread().getState() + " " + i);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }

        }
    }

3、验证waiting状态

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv_button = (TextView) findViewById(R.id.tv_button);
        tv_button1 = (TextView) findViewById(R.id.tv_button1);
        tv_button.setOnClickListener(this);

        MyThread myThread = new MyThread();

        Thread t1 = new Thread(myThread, "用户一");
        Thread t2 = new Thread(myThread, "用户二");
        t1.start();
        t2.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Log.e("sjd====1", "---" + t1.getName() + " " + t1.getState());
        Log.e("sjd====1", "---" + t2.getName() + " " + t2.getState());

    }

    class MyThread implements Runnable {
        @Override
        public void run() {
            synchronized (this) {
                for (int i = 0; i < 10; i++) {
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    Log.e("sjd====", "---" + Thread.currentThread().getName() + " " + Thread.currentThread().getState() + " " + i);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }

        }
    }

4、验证timed_waiting状态

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv_button = (TextView) findViewById(R.id.tv_button);
        tv_button1 = (TextView) findViewById(R.id.tv_button1);
        tv_button.setOnClickListener(this);

//        MyThread t1=new MyThread("男朋友",0);
//        MyThread t2=new MyThread("女朋友",1);
//
//        t1.start();
//        t2.start();

        MyThread myThread = new MyThread();

        Thread t1 = new Thread(myThread, "用户一");
        Thread t2 = new Thread(myThread, "用户二");
        t1.start();
        t2.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Log.e("sjd====1", "---" + t1.getName() + " " + t1.getState());
        Log.e("sjd====1", "---" + t2.getName() + " " + t2.getState());

    }

    class MyThread implements Runnable {
        @Override
        public void run() {
            synchronized (this) {
                for (int i = 0; i < 10; i++) {
                    try {
                        wait(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    Log.e("sjd====", "---" + Thread.currentThread().getName() + " " + Thread.currentThread().getState() + " " + i);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }

        }
    }

九、线程池

1、线程池的优点

  • 单独创建线程缺乏统一管理,线程过多,会造成资源占用过多,可能会导致死机或者oom;
  • 线程池可以使线程重用,控制线程的并发数,提高资源的使用率。

2、线程池类型

2.1、newCachedThreadPool

  • 可缓存线程池,如果线程池长度过处理需要,可灵活回收空闲线程,如果没有可回收的,则新建线程
  • 示例代码:
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            ExecutorService pool= Executors.newCachedThreadPool();
            for (int i=0;i<5;i++){
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                pool.execute(new Mythread());
            }
            pool.shutdown();
        }
    
        class Mythread implements Runnable{
            @Override
            public void run() {
                Log.e("sjd====",Thread.currentThread().getName());
            }
        }
  • 运行结果:(循环开启5个线程,但是线程1回收,又重新使用)

2.2、newFixedThreadPool

  • 固定长度的线程池,可以控制线程最大的并发数,超出的线程在队列中等待
  • 示例代码:
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            ExecutorService pool= Executors.newFixedThreadPool(2);
            for (int i=0;i<5;i++){
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                pool.execute(new Mythread());
            }
            pool.shutdown();
        }
    
        class Mythread implements Runnable{
            @Override
            public void run() {
                Log.e("sjd====",Thread.currentThread().getName());
            }
        }
  • 运行结果:

2.3、newSingleThreadExecutor

  • 创建一个单线程的线程池,只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序执行

2.3、newScheduledThreadPool

  • 创建了一个定长线程池,支持定时以及周期性任务

十、死锁

  • 造成死锁的原因,就是当多个线程各自占有一些资源,并且互相之间还需要其他线程占有的资源才能继续,而导致多个线程都在等待对方释放资源,这种都停止执行的情况,就可能出现死锁的问题。为了更好的理解,下面用图示进行演示:
  • 上面的图示解释:多个线程互相抱着对方需要的资源,形成僵局
  • 模拟死锁的场景:
  • 假如两个人,一个人有面包,想喝牛奶,一个人有牛奶,想吃面包
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        MyThread t1=new MyThread("男朋友",0);
        MyThread t2=new MyThread("女朋友",1);

        t1.start();
        t2.start();

    }

    //面包
    static class Bread{
    }

    //牛奶
    static class Milk{}

     static class MyThread extends Thread{

        static Bread bread=new Bread();
        static Milk milk=new Milk();
        String who;//角色
        int choice;//选择哪个

        MyThread(String who,int choice){
            this.who=who;
            this.choice=choice;
        }
        @Override
        public void run() {
            if (choice==0){
                synchronized (bread){
                    Log.e("sjd====",Thread.currentThread().getName()+"先获得的面包的锁,等待牛奶的锁");
                    try {
                        Thread.sleep(1000);//一秒之后想喝牛奶
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (milk){
                        Log.e("sjd====",Thread.currentThread().getName()+"先获得的牛奶的锁,等待面包的锁");
                    }
                }
            }else {
                synchronized (milk){
                    Log.e("sjd====",Thread.currentThread().getName()+"先获得的牛奶的锁,等待面包的锁");
                    try {
                        Thread.sleep(1000);//一秒之后想吃面包
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (bread){
                        Log.e("sjd====",Thread.currentThread().getName()+"先获得的面包的锁,等待牛奶的锁");
                    }
                }
            }
        }
    }
  • 运行结果:

 解决方案,就是不拿对方的锁

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv_button = (TextView) findViewById(R.id.tv_button);
        tv_button1 = (TextView) findViewById(R.id.tv_button1);
        tv_button.setOnClickListener(this);

        MyThread t1=new MyThread("男朋友",0);
        MyThread t2=new MyThread("女朋友",1);

        t1.start();
        t2.start();

    }

    //面包
    static class Bread{
    }

    //牛奶
    static class Milk{}

    static class MyThread extends Thread{

        static Bread bread=new Bread();
        static Milk milk=new Milk();
        String who;//角色
        int choice;//选择哪个

        MyThread(String who,int choice){
            this.who=who;
            this.choice=choice;
        }
        @Override
        public void run() {
            if (choice==0){
                synchronized (bread){
                    Log.e("sjd====",Thread.currentThread().getName()+"先获得的面包的锁,等待牛奶的锁");
                    try {
                        Thread.sleep(1000);//一秒之后想喝牛奶
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                synchronized (milk){
                    Log.e("sjd====",Thread.currentThread().getName()+"先获得的牛奶的锁,等待面包的锁");
                }
            }else {
                synchronized (milk){
                    Log.e("sjd====",Thread.currentThread().getName()+"先获得的牛奶的锁,等待面包的锁");
                    try {
                        Thread.sleep(1000);//一秒之后想吃面包
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                synchronized (bread){
                    Log.e("sjd====",Thread.currentThread().getName()+"先获得的面包的锁,等待牛奶的锁");
                }
            }
        }
    }

运行结果

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java多线程,Android多线程 的相关文章

随机推荐

  • CSerialPort教程4.3.x (6) - CSerialPort作为第三方库的使用

    CSerialPort教程4 3 x 6 CSerialPort作为第三方库的使用 环境 系统 windows 10 CentOS 7 cmake 3 22 1 前言 CSerialPort项目是一个基于C C 的轻量级开源跨平台串口类库
  • 在linux下如何使用yum查看安装了哪些软件包

    Linux系统下yum命令查看安装了哪些软件包 yum list installed 列出所有已安装的软件包 yum针对软件包操作常用命令 1 使用YUM查找软件包 命令 yum search 2 列出所有可安装的软件包 命令 yum li
  • ubuntu小技巧24--快速入门ffmpeg

    ubuntu小技巧24 快速入门ffmpeg 1 介绍 2 使用方法 2 1 ffmpeg命令剪辑音视频文件 2 2 python脚本剪辑音视频文件 3 注意事项 4 说明 1 介绍 FFmpeg是一套可以用来记录 转换数字音频 视频 并能
  • kernel创建线程

    kernel判断是否是用户进程 之前在上述文章中说到kernel中的线程通过kthreadd创建而来 今天说一下这个过程 static noinline void init refok rest init void int pid rcu
  • librosa安装错误

    一开始的错误 AttributeError type object h5py h5 H5PYConfig has no attribute reduce cython 解决办法 卸载h5py然后安装librosa conda install
  • Python 装饰器详解

    1 为什么需要装饰器 Leader让小A写两个数字相加和相减的函数 小A很快就写完了 def add x y return x y def sub x y return x y if name main result add 1 2 pri
  • SpringBoot多数据源nacos配置

    1 背景 因新项目对旧系统业务的重构 原有业务也只有单一数据源 项目开发到后期 现场存在历史数据迁移问题 在讨论后希望系统支持多数源的方式解决对历史数据同步调用的问题 项目的配置文件为nacos配置 涉及多个现场的升级部署 因此希望改动影响
  • Python爬虫:保姆级教你完成数据存储

    数据存储 在前面的几篇文章中 我分别总结了 什么是爬虫 requests模块总结 正则表达式提取数据 XPath解析数据 Beautiful Soup解析数据 pyquery解析数据 jsonpath提取json数据 在上面的几篇文章当中都
  • 微云网页版服务器繁忙,腾讯微云传输速度慢的几种原因及解决方法

    大家经常使用腾讯微云吧 不过大家知道腾讯微云传输速度慢怎么办吗 下面小编就给大家分享腾讯微云传输速度慢的几种原因及解决方法 希望会对你有所帮助 腾讯微云传输速度慢的几种原因及解决方法 1 网络宽带本身速度慢 解决办法 当处于网络使用高峰期的
  • JMeter 实时监控仪表板配置 (Grafana + InfluxDB)

    在服务器上跑 JMeter 做压测的话 给工具本身也配上实时监控是必须的 命令行输出能提供的信息太少 JMeter的 Backend Listener 支持 Graphite 和 InfluxDB 这里选择 InfluxDB 做时序数据库
  • 【Qt】贴图实现方向控制盘

    版权声明 本文为博主原创文章 遵循 CC 4 0 BY SA 版权协议 转载请附上原文出处链接和本声明 本文链接 https blog csdn net iriczhao article details 122052059 一 效果走一波
  • 【Java基础】Windows快捷键

    Windows常用快捷键以及操作 注 本文内容均来自B站up 遇见狂神说 仅做学习使用 如有侵权删 1 与Ctrl有关的快捷键 Ctrl C 复制 Ctrl V 粘贴 Ctrl X 剪切 Ctrl Z 撤销 Ctrl A 全选 Ctrl S
  • 【吴恩达机器学习笔记】代价函数(一)

    目录 前言 一 单变量线性回归问题 二 建模误差 三 代价函数 平方和误差函数 平均平方和误差 代价函数 四 直观理解代价函数一 五 直观理解代价函数二 三维图像 等高线图 总结 前言 本栏目主要记录吴恩达老师的 机器学习 课程的学习笔记
  • node+axios实现服务端文件上传

    最近调研企业wx集成H5应用 其中有一个发送图文消息 需要上传图片到临时素材库 之前做过文件上传到阿里云 七牛云都是服务端提供封装好的文件上传接口 在客户端使用ajax的方式上传 所以就来踩踩坑 使用node axios实现服务端文件上传
  • Unity3D+Vuforia实现AR效果的案例

    实验步骤 1 打开Unity3D 新建一个项目 下载链接 参考我另一篇文章 Unity3D Vuforia配置 2 导入 import Vuforia包 我这个版本自带Vuforia 如果导入下载的会有冲突 出错 直接按照下图导入 Game
  • QT随机生成验证码 四位数字并 禁止编辑的方法

    随机生成数字 int Widget generateRandomNumber qsrand QTime 0 0 0 secsTo QTime currentTime for int i 0 i lt 4 i int test qrand r
  • 转 C#中的override

    https zhidao baidu com question 446422940 html 要扩展或修改继承的方法 属性 索引器或事件的抽象实现或虚实现 必须使用 override 修饰符 override 方法提供从基类继承的成员的新实
  • Qt跨线程信号和槽的连接

    Qt支持三种类型的信号 槽连接 1 直接连接 当signal发射时 slot立即调用 此slot在发射signal的那个线程中被执行 不一定是接收对象生存的那个线程 2 队列连接 当控制权回到对象属于的那个线程的事件循环时 slot被调用
  • 压测以及python的自省

    经过两个季度的开发 数据库收敛的项目一期终于到了最后阶段 这周完成最后的功能测试之后即将部署到测试环境进行压测 并进行运维文档的完善 下午小组会上 heng哥分享了python类和自省机制的相关内容 他用了苏格拉底那句经典的 The une
  • Java多线程,Android多线程

    目录 一 线程的概念 二 线程创建的方式及特点 三 线程创建方式 1 继承Thread类 2 实现Runnable接口 3 实现Callable接口 我觉得了解即可 4 AsyncTask异步任务 被弃用 5 AsyncTask替代方案 四