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块中释放锁,以确保线程在任何情况下都会释放锁。