说说线程有几种创建方式
有三种:分别是继承Thread类、实现Runnable接口、实现Callable接口。
第一种需要重写父类Thread的run()方法,并且调用start()方法启动线程。
class ThreadTask extends Thread {public void run() {System.out.println("看完⼆哥的 Java 进阶之路,上岸了!");}public static void main(String[] args) {hreadTask task = new ThreadTask();task.start(); }
}
这种方法缺点是,如果ThreadTask已经继承了另外一个类,就不能继承Thread类了,因为Java不支持多重继承。
第二种需要重写Runnable接口的run()方法,并将实现类的对象作为参数传递给Thread对象的构造方法,最后调用start()方法启动线程。
class RunnableTask implements Runnable {public void run() {System.out.println("看完Java 进阶之路,上岸了!");}public static void main(String[] args) {RunnableTask task = new RunnableTask();Thread thread = new Thread(task);thread.start();}
}
这种方法的优点就是可以避免Java的单继承限制,并且更符合面向对象的编程思想,因为Runnable接口将任务代码和线程控制的代码解耦了。
第三种需要重写 Callable 接⼝的 call() ⽅法,然后创建 FutureTask 对象,参数为 Callable 实现类的对象;紧接着创建 Thread 对象,参数为 FutureTask 对象,最后调⽤ start() ⽅法启动线程。
class CallableTask implements Callable<String> {public String call() {return "看完Java 进阶之路,上岸了!";}public static void main(String[] args) throws ExecutionException, InterruptedException {CallableTask task = new CallableTask();FutureTask<String> futureTask = new FutureTask<>(task);Thread thread = new Thread(futureTask);thread.start();System.out.println(futureTask.get());}
}
一个8G的系统最多能创建多少个线程
理论上大约8000个
创建线程的时候,⾄少需要分配⼀个虚拟机栈,在 64 位操作系统中,默认⼤⼩为 1M,因此⼀个线程⼤约需要 1M 的内存。
但 JVM、操作系统本身的运⾏就要占⼀定的内存空间,所以实际上可以创建的线程数远⽐ 8000 少。
详细解释⼀下。
可以通过 java -XX:+PrintFlagsFinal -version | grep ThreadStackSize 命令查看 JVM 栈的默认⼤⼩。
其中 ThreadStackSize 的单位是字节,也就是说默认的 JVM 栈⼤⼩是 1024 KB,也就是 1M。
启动一个Java程序,你能说说里面有哪些线程吗?
首先是main线程,这是程序执行的入口。
然后是垃圾回收线程,它是⼀个后台线程,负责回收不再使⽤的对象。
还有编译器线程,⽐如 JIT,负责把⼀部分热点代码编译后放到 codeCache 中。
可以通过下面的代码检测:
class ThreadLister {public static void main(String[] args) {// 获取所有线程的堆栈跟踪Map<Thread, StackTraceElement[]> threads = Thread.getAllStackTraces();for (Thread thread : threads.keySet()) {System.out.println("Thread: " + thread.getName() + " (ID=" + thread.getId() +")");}}
}
结果如下所示:
Thread: Monitor Ctrl-Break (ID=5)
Thread: Reference Handler (ID=2)
Thread: main (ID=1)
Thread: Signal Dispatcher (ID=4)
Thread: Finalizer (ID=3)
简单解释下:
Thread: main (ID=1) - 主线程,Java 程序启动时由 JVM 创建。
Thread: Reference Handler (ID=2) - 这个线程是⽤来处理引⽤对象的,如软引⽤、弱引⽤和虚引⽤。负责清理被 JVM 回收的对象。
Thread: Finalizer (ID=3) - 终结器线程,负责调⽤对象的 finalize ⽅法。对象在垃圾回收器标记为可回收之前,由该线程执⾏其 finalize ⽅法,⽤于执⾏特定的资源释放操作。
Thread: Signal Dispatcher (ID=4) - 信号调度线程,处理来⾃操作系统的信号,将它们转发给 JVM 进⾏进⼀步处理,例如响应中断、停⽌等信号。
Thread: Monitor Ctrl-Break (ID=5) - 监视器线程,通常由⼀些特定的 IDE 创建,⽤于在开发过程中监控和管理程序执⾏或者处理中断。