android——线程池(单例)、线程1等待线程2执行完才往下走、线程锁(synchronized关键字和ReentrantLock)

1、最简单的线程池使用实例代码:

Runnable run = new Runnable() {
            @Override
            public void run() {
                System.out.println("线程池:");
            }
        };
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MICROSECONDS, new LinkedBlockingDeque<>());
        for (int i = 0; i < 10000; i++) {
            threadPool.execute(run); // 执行线程
        }

如果把new ThreadPoolExecutor放进循环,会造成内存溢出
        for (int i = 0; i < 10000; i++) {ThreadPoolExecutor threadPool = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MICROSECONDS, new LinkedBlockingDeque<>());
            threadPool.execute(run); // 执行线程
        }

所以在我们使用线程池的时候,需要把线程池做成单例(有的同学会想着new一个线程池放到全局来使用,其实正确的做法是做成单例最好),创建的时候定义好多少个线程


import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 线程池初始化类(这是一个单例)
 */
public class ThreadPool {

    //类加载时就初始化,饿汉式单例
    private static final ThreadPool instance = new ThreadPool();

    /**
     * 根据cup核心数设置线程池数量
     */
    private static int corePoolSize = Runtime.getRuntime().availableProcessors();
    /**
     * 最大线程池数量= cpu核心数*2+1
     */
    private static int maximumPoolSize = corePoolSize * 2 + 1;
    /**
     * 等待线程的存活时间
     */
    private static long keepAliveTime = 1;
    /**
     * 等待线程存活时间的单位
     */
    private static TimeUnit timeUnit = TimeUnit.MICROSECONDS;
    private static ThreadPoolExecutor mThreadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, timeUnit, new LinkedBlockingDeque<>()); // 线程池

    private ThreadPool() {
    }

    public static ThreadPoolExecutor getInstance() {
        return mThreadPoolExecutor;
    }

}

使用:

Runnable run=new Runnable() {
            @Override
            public void run() {
                System.out.println("线程:");
            }
        };
        for (int i = 0; i < 10000; i++) {
            ThreadPool.getInstance().execute(run);
        }

kotlin方式的代码:

object ThreadPoolUtils {
    /**
     * 根据cup核心数设置线程池数量
     */
    private val corePoolSize = Runtime.getRuntime().availableProcessors()

    /**
     * 最大线程池数量= cpu核心数*2+1
     */
    private val maximumPoolSize = corePoolSize * 2 + 1

    /**
     * 等待线程的存活时间
     */
    private const val keepAliveTime: Long = 1

    /**
     * 等待线程存活时间的单位
     */
    private val timeUnit: TimeUnit = TimeUnit.MICROSECONDS
    private val mThreadPoolExecutor: ThreadPoolExecutor = ThreadPoolExecutor(
        corePoolSize,
        maximumPoolSize,
        keepAliveTime,
        timeUnit,
        LinkedBlockingDeque()
    ) // 线程池

    fun getInstance(): ThreadPoolExecutor {
        return mThreadPoolExecutor
    }

    fun execute(command: Runnable) {
        mThreadPoolExecutor.execute(command)
    }
}

使用:

        val thead = Runnable {
            while (true) {
                Log.i("wy", "运行线程池")
                Thread.sleep(10000);//休眠3秒
            }
        }
        repeat(100){
            ThreadPoolUtils.execute(thead)
        }

2、线程1等待线程2执行完才往下走

代码:

        val thread2 = Thread {
            sleep(30 * 1000)
            Log.e("TAG", "thread2==>")
        }

        val thread1 = Thread {
            sleep(10 * 1000)
            try {
                Log.e("TAG", "thread1==>1")
                thread2.join() // 等待线程thread2执行完成才往下走
                Log.e("TAG", "thread1==>2")
            } catch (e: InterruptedException) {
                e.printStackTrace()
            }
        }

        thread1.start()
        thread2.start()

执行结果:

3、线程锁(解决2的问题)

Java双线程并行加锁可以使用synchronized关键字或者ReentrantLock类来实现。下面分别介绍两种实现方式:

一、使用synchronized关键字

synchronized关键字可以通过多个线程共享同一个锁对象,来实现线程同步。在Java中,每个对象都有一个锁,当一个线程访问该对象时,会获得该对象的锁,其他线程则无法访问该对象。当线程访问完该对象后,会释放该对象的锁,其他线程就可以继续访问该对象了。

下面是使用synchronized关键字实现双线程并行加锁的示例代码:

public class SynchronizedDemo {
    public static void main(String[] args) {
        final Object lock = new Object();
        Thread thread1 = new Thread(() -> {
            synchronized (lock) { // 拿到lock锁
                for (int i = 0; i < 10; i++) {
                    System.out.print("A");
                }
                System.out.println();
            } // 释放lock锁
        });
        Thread thread2 = new Thread(() -> {
            synchronized (lock) { // 拿到lock锁
                for (int i = 0; i < 10; i++) {
                    System.out.print("B");
                }
                System.out.println();
            } // 释放lock锁
        });
        thread1.start();
        thread2.start();
    }
}

上述代码中,我们使用了一个Object类型的对象lock作为共享的锁对象,每个线程都需要先获取lock对象的锁才能执行后续的操作。当线程1拿到锁后,先输出10个字母"A",然后释放锁,线程2才能拿到锁,输出10个字母"B",最终输出的结果为:

AAAAAAAAAA
BBBBBBBBBB

如果不加锁则会输出

 

二、使用ReentrantLock类

ReentrantLock类是Java提供的一个可重入锁类,与synchronized关键字类似,可以通过多个线程共享同一个锁对象,来实现线程同步。

下面是使用ReentrantLock类实现双线程并行加锁的示例代码:

import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockDemo {
    public static void main(String[] args) {
        final ReentrantLock lock = new ReentrantLock();
        Thread thread1 = new Thread(() -> {
            lock.lock();
            try {
                for (int i = 0; i < 10; i++) {
                    System.out.print("A");
                }
                System.out.println();
            } finally {
                lock.unlock();
            }
        });
        Thread thread2 = new Thread(() -> {
            lock.lock();
            try {
                for (int i = 0; i < 10; i++) {
                    System.out.print("B");
                }
                System.out.println();
            } finally {
                lock.unlock();
            }
        });
        thread1.start();
        thread2.start();
    }
}

上述代码中,我们使用了一个ReentrantLock类型的对象lock作为共享的锁对象,每个线程都需要先获取lock对象的锁才能执行后续的操作。当线程1拿到锁后,先输出10个字母"A",然后释放锁,线程2才能拿到锁,输出10个字母"B",最终输出的结果与前面的示例相同。

需要注意的是,在使用ReentrantLock时,需要在finally块中释放锁,以确保线程在任何情况下都会释放锁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wy313622821

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值