创建线程的日常错误说法
所谓错误说法,并不是说方法就是错误的;只是相对于实现Runnable()接口和继承Thread类来说,这些都不是新的创建线程的方式。
- 线程池创建多线程
//线程池方式创建多线程 public static void main(String[] args) { ExecutorService executorService = Executors.newCachedThreadPool(); for (int i = 0; i < 1000; i++) { executorService.submit(new Task() { }); } } static class Task implements Runnable{ @Override public void run() { try { Thread.sleep(5000); }catch (InterruptedException e){ e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); } } 复制代码
解答:
利用线程池方式创建多线程并非新的创建方式,究其本质,线程池需要一个线程工厂创建线程,线程工厂创建线程用的还是new 一个 Thread并传入Runnable方法。
//Executors源码 static class DefaultThreadFactory implements ThreadFactory { private static final AtomicInteger poolNumber = new AtomicInteger(1); private final ThreadGroup group; private final AtomicInteger threadNumber = new AtomicInteger(1); private final String namePrefix; DefaultThreadFactory() { SecurityManager s = System.getSecurityManager(); group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); namePrefix = "pool-" + poolNumber.getAndIncrement() + "-thread-"; } public Thread newThread(Runnable r) { Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0); if (t.isDaemon()) t.setDaemon(false); if (t.getPriority() != Thread.NORM_PRIORITY) t.setPriority(Thread.NORM_PRIORITY); return t; } } 复制代码
2.无返回值是实现runnable接口,有返回值是实现callable接口,所以callable是新的实现线程方式
public static void main(String[] args) throws Exception { FutureTask futureTask = new FutureTask(new MyThread()); new Thread(futureTask).start(); System.out.println("【数据返回】"+ futureTask.get()); } static class MyThread implements Callable<String>{ @Override public String call() throws Exception { for (int i = 0; i < 100; i++) { System.out.println("线程执行 + "+i); } return "多线程返回真牛逼"; } } 复制代码
源码解答:
FutureTask类实现了RunnableFuture接口,然后RunnableFuture接口继承自Runnable接口和Future接口;其中Runnable接口负责Run方法,Future接口负责get方法返回;究其本质,还是创建了一个Thread类并传入Runnable实现多线程 3.计时器创建线程
public static void main(String[] args) { Timer timer = new Timer(); timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { System.out.println(Thread.currentThread().getName()); } },1000,1000); } 复制代码
源码解答:
TimerTask类实现了Runnable对象,究其本质,还是Runnable对象
- 匿名内部 包装都没有,只是语法层面上的转换
- lambda 包装都没有,只是语法层面上的转换
关于停止线程的正确方式————常见面试题
- 如何停止线程
- 原理:用interrupt请求、好处 → 可以保证数据安全等等,把主动交给被中断的线程
- 想停止线程,要请求方、被停止方、子方法(优先抛出异常配合处理,或者捕获收到中断信号后再次设为中断状态)被调用方相互配合
- 最后再说错误的方法:stop/suspend已废弃,volatile的boolean无法处理长时间的阻塞情况
- 如何处理不可中断 的阻塞
如果线程阻塞是因为由于调用了wait()、sleep()或join()方法,你可以中断线程,通过抛出InterruptedException异常来唤醒该线程。 但是对于不能响应InterruptedException的阻塞,很遗憾,并没有一个通用的解决方案,但是我们可以利用特定的其他可以响应中断的方法。比如 ReentrantLock.lockInterruptibly(),比如关闭套接字使线程立即返回等方法来达到目的。 答案有很多种,因为有很多原因会导致线程阻塞,所以针对不同的情况,唤起的方法也不同。
作者:Jayhaw_花
链接:https://juejin.cn/post/6994075101259890724
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。