class LiftOff extends Thread{
private int countDown=3;
private static int taskCount=0;
private final int id=taskCount++;
@Override
public void run() {
while (countDown–>0) {
System.out.println(“#id=” + id + " countDown="+(countDown > 0 ? countDown : “LiftOff!”));
Thread.yield();
}
}
}
4、线程池
待续…
5、从任务中产生返回值—Callable接口
package com.duoxiancheng;
import java.util.concurrent.*;
public class Main1 {
public static void main(String[] args) throws Exception{
ExecutorService executorService= Executors.newCachedThreadPool();
for (int i=0;i<50;i++){
Future future = executorService.submit(new TaskWithResult(i));
Object result = future.get();
System.out.println(result);
}
}
}
class TaskWithResult implements Callable{
private int id=0;
public TaskWithResult(int id){[br/>this.id=id;
}
@Override
public Object call() throws Exception {
return id;
}
}](mailto:br/)
其中 future.get()是阻塞的方法;如果想想立即阻塞任务的等待,则可以使用 result = exec.submit(aCallable).get(); 形式
6、常用方法
休眠—sleep()
让步—yield()
加入一个线程—join()
优先级–setPriority()/getPriority()
后台线程–setDaemon()/isDaemon()
…
7、捕获线程中的异常
线程中抛出异常,会传播到控制台,除非采用特殊手段。
public interface Runnable {
public abstract void run();
}
在run()方法内部try-catch-finally捕获异常
使用异常处理器捕获异常–异常处理器实现Thread.UncaughtExceptionHandler接口
以下分析自定义异常处理器:
为线程设置异常处理器。具体做法可以是以下几种:
(1)Thread.setUncaughtExceptionHandler设置当前线程的异常处理器;
(2)Thread.setDefaultUncaughtExceptionHandler为整个程序设置默认的异常处理器;
如果当前线程有异常处理器(默认没有),则优先使用该UncaughtExceptionHandler类;否则,如果当前线程所属的线程组有异常处理器,则使用线程组的
UncaughtExceptionHandler;否则,使用全局默认的DefaultUncaughtExceptionHandler;如果都没有的话,子线程就会退出
package com.duoxiancheng;
import java.util.concurrent.ThreadFactory;
public class Main2 {
public static void main(String[] args) {
Thread thread=new Thread(new ExceptionThread());
thread.setUncaughtExceptionHandler(new MyExceptionHandler());
thread.start();
}
}
/**
- 任务类
\*/
class ExceptionThread implements Runnable{
@Override
public void run() {
Thread t = Thread.currentThread();
System.out.println("ExceptionThread 当前线程信息:"+t.toString());
System.out.println("当前线程ExceptionThread的异常处理器"
+t.getUncaughtExceptionHandler());
throw new RuntimeException();
}
}
/**
- 线程异常处理器
\*/
class MyExceptionHandler implements Thread.UncaughtExceptionHandler {[br/>@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("抛出的异常是:"+e);
}
}](mailto:br/)
8、共享资源
共享资源竞争:
导致线程安全问题
解决思想:
多人(线程)都希望单独使用浴室(共享资源)。为了使用浴室,一个人先敲门,看能不能使用。如果没人回话,他就进入浴室并锁上门(获得锁)。这时候,其它人想使用浴室的话,就会被阻挡在外面(不能获取锁),直到浴室可以使用。浴室外面的人没有排队,浴室门打开(前一个人释放锁),离门最近的人优先进入使用(获得锁,设置优先级和yield方法可以建议某个优先使用)。
解决方式:
Synchronized 、Lock锁同步以及Voliate修饰符和原子类
线程本地存储—ThreadLocal
9、线程之间协作
生产者与消费者
package com.duoxiancheng;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
- 生产者-消费者
\*/
public class Main3 {
public static void main(String\[ \] args) throws InterruptedException {
Restaurant restaurant=new Restaurant();
new Thread(new ProductorThread(restaurant)).start();
Thread.sleep(20);
new Thread(new ConsumerThread(restaurant)).start();
}
}
class Restaurant {
Lock lock=new ReentrantLock();//锁
Condition condition1=lock.newCondition();//条件1
Condition condition2=lock.newCondition();//条件2
private int count;//已做好的餐
private int count2;
/\*\*
* 消费者方法
\*/
public void comsumer(){
lock.lock();
try {
if (count==0) {
System.out.println(Thread.currentThread().getId()+"客户 想要一份快餐!");
condition2.signalAll();
System.out.println(Thread.currentThread().getId()+"客户 等待一份快餐!");
condition1.await();
}
count--;
System.out.println(Thread.currentThread().getId()+ "客户 消费了一份快餐!");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
/\*\*
* 生产者方法
\*/
public void productor(){
lock.lock();
try {
condition2.await();
count++;//生产一份快餐
System.out.println(Thread.currentThread().getId()+ "厨师 制作了一份快餐!");
condition1.signalAll();
System.out.println(Thread.currentThread().getId()+"厨师 通知客户使用");
}catch (InterruptedException e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
/**
- 消费者
\*/
class ConsumerThread implements Runnable{
private Restaurant restaurant;
public ConsumerThread(Restaurant restaurant){
this.restaurant=restaurant;
}
@Override
public void run() {
restaurant.comsumer();
}
}
/**
- 生产者
\*/
class ProductorThread implements Runnable{
private Restaurant restaurant;
public ProductorThread(Restaurant restaurant){
this.restaurant=restaurant;
}
@Override
public void run() {
restaurant.productor();
}
}
输出结果:
11客户 想要一份快餐!
11客户 等待一份快餐!
10厨师 制作了一份快餐!
10厨师 通知客户使用
11客户 消费了一份快餐!
生产者与消费者 和 队列
使用wait()、notifyAll() 是一种解决任务互操作问题非常低级的方式。使用同步队列来解决任务协作问题,同步队列在任何时刻只允许一个任务插入或移除。
java.util.concurrent.BlockingQueue接口提供了这个同步队列,其有大量的实现。通常可以使用LinkedBlockingDeque(×××队列) 和 ArrayBlockingDeque(固定尺寸队列)。
消费者任务试图从队列中获取对象,而该队列此时为空,那这些队列还可以挂起消费者任务(阻塞);当有更多元素可用时恢复消费者任务。阻塞队列可以解决非常大量的问题。
package com.duoxiancheng;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
/**
- 生产者-消费者与队列
\*/
public class Main4 {
public static void main(String\[\] args) {
ExecutorService executorService= Executors.newCachedThreadPool();
LinkedBlockingDeque<Toast> toastQueue=new LinkedBlockingDeque<>();
LinkedBlockingDeque<Toast> butteredQueue=new LinkedBlockingDeque<>();
LinkedBlockingDeque<Toast> jammedQueue=new LinkedBlockingDeque<>();
executorService.execute(new Toaster(toastQueue));
executorService.execute(new Butterer(toastQueue, butteredQueue));
executorService.execute(new Jammed(butteredQueue, jammedQueue));
executorService.execute(new Eater(jammedQueue));
}
}
class Toast{
private Status status=Status.DRY;
private final int id;
public Toast(int id) {
this.id = id;
}
public int getId() {
return id;
}
public Status getStatus() {
return status;
}
public void addButtered(){
status=Status.BUTTERED;
}
public void addJammed(){
status=Status.JAMMED;
}
@Override
public String toString() {
return "Toast "+id+" : "+status;
}
/**
- 枚举类型
*/
public enum Status{
DRY,BUTTERED,JAMMED
}
}
/**
- 制作吐司
\*/
class Toaster implements Runnable{
private LinkedBlockingDeque<Toast> toastQueue;
private int count;
public Toaster(LinkedBlockingDeque toastQueue){[br/>this.toastQueue=toastQueue;
}
@Override
public void run() {
try {
for (int i = 0; i < 5; i++) {
Toast toast = new Toast(count++);
System.out.println(toast);
toastQueue.put(toast);
Thread.sleep(100);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}](mailto:br/)
/**
- 添加黄油
\*/
class Butterer implements Runnable{
private LinkedBlockingDeque<Toast> toastQueue;
private LinkedBlockingDeque<Toast> butteredQueue;
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Java开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
{
private LinkedBlockingDeque<Toast> toastQueue;
private LinkedBlockingDeque<Toast> butteredQueue;
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-Y5DLbXLo-1715709105953)]
[外链图片转存中…(img-3A3BeVwv-1715709105953)]
[外链图片转存中…(img-HjUAeRSd-1715709105953)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Java开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!