JAVA面试题总结-多线程(41-48)

41.sleep() 和 wait() 有什么区别?

sleep()是Thread类中的方法,wait()是Object类中的方法。

sleep()不释放锁,wait()释放锁。

sleep()在任何地方都能使用,而wait()只能在同步方法或代码块中使用。

sleep()在设置的时间过后会重新竞争资源,而wait()必须由notify()或notifyAll()方法来释放。

42.notify()和 notifyAll()有什么区别?

notify和notifyAll都是用来唤醒被wait方法执行的线程。

notify是唤醒当前共享资源上随机一个被wait()的线程。

notifyAll是唤醒当前共享资源上所有被wait()的线程.

43.线程的 run()和 start()有什么区别?

run()方法是执行线程体中的代码,start()是启动线程

正常的顺序是用start()启动线程,每一个线程抢占到CPU之后执行run()方法,这样才有多线程的效果。

如果直接执行run()方法就相当于直接将一个线程执行,这就相当于单线程执行。

44.创建线程池有哪几种方式?

ThreadPoolExecutor():最原始的线程池创建。

newFixedThreadPool(int nThreads):固定线程数的线程池。适用于负载比较重的服务器。

newCachedThreadPool():按照需要创建新线程的线程池。该线程池可以无限扩展,当需求增加时,可以添加新的线程,而当需求降低时会自动回收空闲线程,适用于执行很多的短期异步操作,或者是负载较轻的服务器。

newSingleThreadExecutor():只有一个线程的线程池。适用于需要保证顺序执行各个任务的场景。

45.线程池都有哪些状态?

线程池有五种状态,它是在ThreadPoolExecutor类中定义的常量

RUNNING:创建线程池之后的初始状态,这种状态下可以执行任务。

SHUTDOWN:该状态下线程池不会再接收新任务,但是会将工作队列中的任务执行完毕。

STOP:该状态下线程池不会再接收新任务的同时也不会处理工作队列中的剩余任务,并且会中断所有工作线程。

TIDYING:该状态下所有任务都已终止或者处理完成,将会执行terminated()钩子方法。

TERMINATED:执行完terminated()钩子方法之后的状态,terminated钩子方法是在Executor终止时调用,默认实现不执行操作。

线程池的状态转换规则:

线程池创建之后状态为RUNNING;

RUNNING状态下,执行shutdown()方法,会使线程池由RUNNING状态转为SHUTDOWN状态;

RUNNING状态下,执行shutdownNow()方法,会使线程池由RUNNING状态转为STOP状态;

SHUTDOWN状态下,执行shutdownNow()方法,会使线程池由SHUTDOWN状态转为STOP状态;

等待线程池中的任务线程停止,工作队列清空之后,会使线程池由STOP状态转为TIDYING状态;

执行完terminated()钩子方法之后,会使线程池由TIDYING状态转为TERMINATED状态。

46.线程池中 submit()和 execute()方法有什么区别?

execute()方法位于接口Executor中,而submit()方法位于AbstractExecutorService中。

execute()的参数只可以使Runnable类型,而submit()重载了三个方法,参数可以是Runnable类型,也可以是Callable类型,也可以是Runnable+结果。

execute()方法没有返回值,而submit()方法有返回值。

submit()底层是调用execute()方法。

47.在 java 程序中怎么保证多线程的运行安全?

线程的安全问题体现在三个方面:

线程切换导致的原子性问题:要不都执行要不都不执行。JDK Atomic开头的原子类、synchronized、LOCK可以解决。

缓存导致的可见性问题:一个线程对共享变量的修改,其他线程能够立即看到。synchronized、LOCK、volatile可以解决。

编译优化导致的有序性问题:程序执行顺序按照代码的先后顺序执行。volatile可以解决。

48.多线程锁的升级原理是什么?

没有优化锁之前,synchronized是重量级锁(悲观锁),使用wait和notify或notifyAll来切换线程状态,非常耗费资源影响性能,所以在JDK6对synchronized关键字进行优化,从锁级别从低到高分为:无锁、偏向锁、轻量级锁、重量级锁。锁升级是不可逆的。

java面试题真的很多,下面我来回答一个有关多线程的问题。 在Java实现多线程有两种方式,一种是继承Thread类,另一种是实现Runnable接口。这两种方式有何区别? 继承Thread类的方式是直接定义一个类继承Thread,并重写它的run()方法。然后创建该类的对象,并调用对象的start()方法来启动线程。这种方式简单直接,但因为Java是单继承的,所以如果某个类已经继承了其他类,就不能再直接继承Thread类实现多线程。 实现Runnable接口的方式是定义一个类实现Runnable接口,并实现其唯一的抽象方法run()。然后创建Thread类的对象,将实现了Runnable的对象作为参数传递给Thread类的构造方法。最后调用Thread对象的start()方法来启动线程。这种方式灵活性更大,因为Java允许一个类实现多个接口,所以即使某个类已经继承了其他类,仍然可以通过实现Runnable接口来实现多线程。 另一个区别在于资源共享的问题。继承Thread类的方式,不管是数据还是方法,都是线程自己拥有的,不存在共享的情况。而实现Runnable接口的方式,多个线程可以共享同一个对象的数据和方法,因为多个线程共同操作的是同一个Runnable对象。 总结来说,继承Thread类方式简单直接,但只能通过单继承来实现多线程;实现Runnable接口方式更灵活,可以解决单继承的限制,并且多个线程可以共享同一个Runnable对象的数据和方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值