线程通讯:
在多线程中,某个线程进入“等待状态”时,需要某个线程来唤醒
等待方法:
wait()//无线等待wait(long 毫秒)//计时等待
注意,调用wait方法,会自动释放掉锁资源
处于wait状态只能由其他线程唤醒
唤醒方法:
notify();//唤醒处于“等待状态”的任意一个线程,和notify使用相同锁对象的线程notifyAll();//唤醒处于“等待状态”的所有线程
注意,调用notify(),notifyAll()方法,不会自动释放掉锁资源
使用细节:
等待和唤醒的方法,都要使用锁对象调用(需要在同步代码块中使用)
等待和唤醒方法都应该使用相同的锁对象调用
消费者,生产者模型:
//共享资源
public class Resource {
static public int number=0;
}
public class test2 {
public static void main(String[] args) {
Object lock=new Object();
//创建消费者线程
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
synchronized (lock) {
if (Resource.number >= 3) {
System.out.println("这有足够多的食物");
try {
lock.wait();//阻塞并释放锁
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
} else {
Resource.number++;//,一开时number=0,先++再打印
System.out.println("[p]:" + Resource.number);
lock.notify();//唤醒处于等待状态的线程,且不会释放锁
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
}
}).start();
Runnable task=new Runnable() {
@Override
public void run() {
while (true) {
synchronized (lock) {
if(Resource.number==0)
{
System.out.println("这没有足够的资源");
try {
lock.wait();//阻塞的同时会释放掉锁
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
else {
System.out.println("[c]"+Resource.number);//先打印,再--
Resource.number--;
lock.notify();//唤醒生产者线程,生产者如果没有处于等待,就没事
//只能唤醒别的线程
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
}
};
new Thread(task).start();
}
}
线程池:
如何获得线程池对象:
方式一:使用ExecutorService的实现类ThreadPoolExecutor自创建一个线程池对象
计算密集型任务:核心线程数:cpu数+1
IO密集型任务:核心线程数:cpu数*2
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
参数一: corePoolSize:指定线程池的核心线程的数量
参数二:maximumPoolSize:指定线程池的最大线程数量
参数三: long keepAliveTime:指定临时线程的存活时间(没有事情干)
参数四:unit:指定临时线程的存活时间单位(分,秒,天)
参数五:workQueue:指定线程池的任务队列
参数六:threadFactory:指定线程池的线程工厂
参数七: handler:指定线程池的任务拒接策略
例如:
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3, 5, 8, TimeUnit.MINUTES, new ArrayBlockingQueue<>(4), Executors.defaultThreadFactory(),// // Executors.defaultThreadFactory()获取默认的线程池工厂 new ThreadPoolExecutor.AbortPolicy());
临时线程什么时候创建:
新任务提交时发现核心线程都在忙,任务对列也满了,并且还可以创建临时线程
什么时候拒绝新任务:
核心线程和临时线程都满了,任务队列也满了
一个任务类:
public class Task1 implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"输出yyyy");
try{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
public class test {
public static void main(String[] args) {
//创建一个线程池对象
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3, 5, 8, TimeUnit.MINUTES,
new ArrayBlockingQueue<>(4), Executors.defaultThreadFactory(),// // Executors.defaultThreadFactory()获取默认的线程池工厂
new ThreadPoolExecutor.AbortPolicy());
//添加任务
threadPoolExecutor.execute(new Task1());//线程池会自动创建一个线程,自动处理任务
threadPoolExecutor.shutdown();//等待线程池所有任务执行完后关闭线程池
threadPoolExecutor.shutdownNow();//立即关闭线程池
}
}
方式二:使用Executors工具类
public static ExecutorService newFixedThreadPool(int nThreads)
创建固定线程数量的线程池,如果某个线程因为异常关闭,那么线程池会创建出一个新的线程
public static ExecutorService newSingleThreadExecutor()
创建只有一个线程的线程池, 如果这个线程因为异常关闭,那么线程池会创建出一个新的线程
Callable任务:
Interface Callable<V>
Callable支持结果返回,Runnable不行
Callable可以抛出异常,Runnable不行
Callable任务处理使用步骤:
1:创建线程池
2:定义Callable任务
3:创建Callable任务,提交任务给线程池
4:获取执行结果
public class test2 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//创建线程池对象
ExecutorService executorService = Executors.newFixedThreadPool(10);
//创建一个Callable类型的任务类
Callable<Integer>callable=new Callable<Integer>() {
@Override
public Integer call() throws Exception {
int sum=0;
for(int i=0;i<10;i++)
{
sum+=i;
}
return sum;
}
};
//交给线程池处理(submit()方法),并获取返回值
Future<Integer> submit = executorService.submit(callable);
System.out.println(submit.get());//通过get方法获取返回值
}
}