关于Java核心面试知识点,已经讲到了Java多线程并发,由于Java多线程并发内容较多,这章我将分为三篇文章来讲,各位记得关注霸哥,上车不跟丢!
故事小情节:
一个程序员去公司面试,本想穿着整齐,给面试官一个好印象,但没想到被面试官瞧不起了…
面试官:这位同志,我们这里招Java高级工程师,你是不是走错了?
程序员:没有啊,我接到面试通知来的…
面试官:好吧,咱们这就开始吧!
程序员:好的
面试官:你之前做过哪些项目?
程序员:我一共主持开发过5个大型项目,若干个小项目,其中使我记忆最深刻的是…,当时我们运用了…技术,并发量提升了…
面试官:那你来讲讲Java中的多线程并发问题?
程序员:这个…
面试官:怎么了?讲不出来?我就知道…
程序员摘下帽子
程序员:Java多线程并发我能讲3个小时,你确定要听?
1、继承 Thread 类
Thread 类本质上是实现了 Runnable 接口的一个实例,代表一个线程的实例。启动线程的唯一方法就是通过 Thread 类的 start()实例方法。start()方法是一个 native 方法,它将启动一个新线程,并执行 run()方法。
public class MyThread extends Thread {
public void run() {
System.out.println("MyThread.run()");
}
}
MyThread myThread1 = new MyThread();
myThread1.start();
2、实现 Runnable 接口
如果自己的类已经 extends 另一个类,就无法直接 extends Thread,此时,可以实现一个Runnable 接口。
public class MyThread extends OtherClass implements Runnable {
public void run() {
System.out.println("MyThread.run()");
}
}
//启动 MyThread,需要首先实例化一个 Thread,并传入自己的 MyThread 实例:
MyThread myThread = new MyThread();
Thread thread = new Thread(myThread);
thread.start();
//事实上,当传入一个 Runnable target 参数给 Thread 后,Thread 的 run()方法就会调用
target.run()
public void run() {
if (target != null) {
target.run();
}
}
3、ExecutorService、Callable、Future 有返回值线程
有返回值的任务必须实现 Callable 接口,类似的,无返回值的任务必须 Runnable 接口。执行Callable 任务后,可以获取一个 Future 的对象,在该对象上调用 get 就可以获取到 Callable 任务返回的 Object 了,再结合线程池接口 ExecutorService 就可以实现传说中有返回结果的多线程了。
//创建一个线程池
ExecutorService pool = Executors.newFixedThreadPool(taskSize);
// 创建多个有返回值的任务
List list = new ArrayList();
for (int i = 0; i < taskSize; i++) {
Callable c = new MyCallable(i + " ");
// 执行任务并获取 Future 对象
Future f = pool.submit(c);
list.add(f);
}
// 关闭线程池
pool.shutdown();
// 获取所有并发任务的运行结果
for (Future f : list) {
// 从 Future 对象上获取任务的返回值,并输出到控制台
System.out.println("res:" + f.get().toString());
}
4、基于线程池的方式
线程和数据库连接这些资源都是非常宝贵的资源。那么每次需要的时候创建,不需要的时候销毁,是非常浪费资源的。那么我们就可以使用缓存的策略,也就是使用线程池。
// 创建线程池
ExecutorService threadPool = Executors.newFixedThreadPool(10);
while(true)
{
threadPool.execute(new Runnable()
{ //提交多个线程任务,并执行
@Override
public void run()
{
System.out.println(Thread.currentThread().getName() + " is running ..");
try
{
Thread.sleep(3000);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
});
}
Java 里面线程池的顶级接口是 Executor,但是严格意义上讲 Executor 并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是 ExecutorService。
1、newCachedThreadPool
创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。对于执行很多短期异步任务的程序而言,这些线程池通常可提高程序性能。调用 execute 将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。因此,长时间保持空闲的线程池不会使用任何资源。
2、newFixedThreadPool
创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。在任意点,在大多数 nThreads 线程会处于处理任务的活动状态。如果在所有线程处于活动状态时提交附加任务,则在有可用线程之前,附加任务将在队列中等待。如果在关闭前的执行期间由于失败而导致任何线程终止,那么一个新线程将代替它执行后续的任务(如果需要)。在某个线程被显式地关闭之前,池中的线程将一直存在。
3、newScheduledThreadPool
创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
scheduledThreadPool.schedule(newRunnable()
{
@Override
public void run()
{
System.out.println("延迟三秒");
}
}, 3, TimeUnit.SECONDS);
scheduledThreadPool.scheduleAtFixedRate(newRunnable()
{
@Override
public void run()
{
System.out.println("延迟 1 秒后每三秒执行一次");
}
}, 1, 3, TimeUnit.SECONDS);
4、newSingleThreadExecutor
Executors.newSingleThreadExecutor()返回一个线程池(这个线程池只有一个线程),这个线程池可以在线程死后(或发生异常时)重新启动一个线程来替代原来的线程继续执行下去!
为了避免文章篇幅过长,下面的章节就简单介绍,不一一将小节内容发出来了!需要的话可以后台私信【Java】免费领取PDF文档!
当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态。在线程的生命周期中,它要经过新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)5 种状态。尤其是当线程启动以后,它不可能一直"霸占"着 CPU 独自运行,所以 CPU 需要在多条线程之间切换,于是线程状态也会多次在运行、阻塞之间切换。
1.对于 sleep()方法,我们首先要知道该方法是属于 Thread 类中的。而 wait()方法,则是属于Object 类中的。
2.sleep()方法导致了程序暂停执行指定的时间,让出 cpu 该其他线程,但是他的监控状态依然保持着,当指定的时间到了又会自动恢复运行状态。
3.在调用 sleep()方法的过程中,线程不会释放对象锁。
4.而当调用 wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用 notify()方法后本线程才进入对象锁定池准备获取对象锁进入运行状态。
1.start()方法来启动线程,真正实现了多线程运行。这时无需等待 run 方法体代码执行完毕,可以直接继续执行下面的代码。
2.通过调用 Thread 类的 start()方法来启动一个线程, 这时此线程是处于就绪状态, 并没有运行。
3.方法 run()称为线程体,它包含了要执行的这个线程的内容,线程就进入了运行状态,开始运行 run 函数当中的代码。 Run 方法运行结束, 此线程终止。然后 CPU 再调度其它线程。
守护线程–也称“服务线程”,他是后台线程,它有一个特性,即为用户线程提供公共服务,在没有用户线程可服务时会自动离开。
线程相关的基本方法有 wait,notify,notifyAll,sleep,join,yield 等。
针对于Java程序员,我这边还准备免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)
学习视频和面试PDF都是可以免费分享的,希望能够帮助到有需要的朋友,同时也节省了大家再去网上找资料的时间。
评论区获取领取方式