java多线程基础
【前言】一直很想总结下java面试中常见的一些面试问题,这里开个头,新的一年,开始好好写博客,好好总结,准备迎接各种面试了。首先写java多线程系列01——多线程基础知识,多线程向来是企业面试编程技术的最长见的题目了,不管是单独问还是嵌入到项目中问,反正都会问问。
1、java多线程知识总览
这个表格中列出了java多线程中经常涉及到的一些技术,其中包括了几个5个部分,基本上都是常见的一些操作了。这里在java多线程系列中一一写到。
2、线程基础
进程:计算机中正在执行的程序
线程:执行进程的基本单元
【 理解】也就是说进程中有可以有一个或者多个线程,如果只有一个线程就称之为单线程程序,如果有多个线程就称之为多线程程序。2.1、线程的创建和运行
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class NewThreadDemo {
public static void main(String[] args) throws InterruptedException, ExecutionException {
Thread t1 = new Thread(){//第一种方式
@Override
public void run() {
System.out.println("new Thread 1");
}
};//创建线程
t1.start();//启动线程
// System.out.println(t1.getName());
Thread t2 = new Thread(new Runnable() {//第二种方式
@Override
public void run() {
System.out.println("new Thread 2");
}
});
t2.start();
//重要方法:Thread.currentThread()
//System.out.println(Thread.currentThread().getName());
//第三种方式
FutureTask<String> ft = new FutureTask<String>(new Callable<String>() {
@Override
public String call() throws Exception {
System.out.println("new Thread 3");
return "aaaa";
}
});
Thread t3 = new Thread(ft);
t3.start();
String result = ft.get();
System.out.println(result);
}
}
【总结】
创建线程的方式:
1.继承Thread类,并复写run方法,创建该类对象,调用start方法开启线程。
2.实现Runnable接口,复写run方法,创建Thread类对象,讲Runnable子类对象传递给Thread类对象。调用start方法开启线程。
第二种方式好,将线程对象和线程任务对象分离开。降低了耦合性,利于维护
3.创建FutureTask对象,创建Callable子类对象,复写call(相当于run)方法,将其传递给FutureTask对象(相当于一个Runnable)。
创建Thread类对象,将FutureTask对象传递给Thread对象。调用start方法开启线程。这种方式可以获得线程执行完之后的返回值。2.2、线程信息的获取
【常见的四种线程信息】
public class ThreadInfo {
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
//演示WATITING状态
@Override
public void run() {
synchronized (ThreadInfo.class) {
System.out.println("Thread");
}
}
});
t1.start();
System.out.println(t1.getId());
System.out.println(t1.getName());
System.out.println(t1.getPriority());//优先级 1-10
System.out.println(t1.getState());//线程状态: NEW TERMINATED RUNNABLE TIMED_WAITING WAITING BLOCKED
}
}
【补充知识点】线程状态
NEW | 至今尚未启动的线程处于这种状态 |
RUNNABLE | 正在 Java 虚拟机中执行的线程处于这种状态 |
BLOCKED | 受阻塞并等待某个监视器锁的线程处于这种状态 |
WAITING | 无限期地等待另一个线程来执行某一特定操作的线程处于这种状态 |
TIMED_WAITING | 等待另一个线程来执行取决于指定等待时间的操作的线程处于这种状态 |
TERMINATED | 已退出的线程处于这种状态 |
【图】线程状态信息
2.3、线程休息(工具类TimeUnit的使用)
import java.util.concurrent.TimeUnit;
public class ThreadSleepDemo {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("游戏开始!");
for (int i = 5; i >= 1; i--) {
System.out.println(i+"...");
try {
//Thread.sleep(1000);
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
【TimeUnit】
表示给定单元粒度的时间段,它提供在这些单元中进行跨单元转换和执行计时及延迟操作的实用工具方法。用法见上例(主要是要记住有这么个方便的工具类即可)2.4、线程组
线程组表示一个线程的集合。此外,线程组也可以包含其他线程组。线程组构成一棵树,在树中,除了初始线程组外,每个线程组都有一个父线程组。
允许线程访问有关自己的线程组的信息,但是不允许它访问有关其线程组的父线程组或其他任何线程组的信息。public class ThreadGroupDemo {
public static void main(String[] args) {
Thread main = Thread.currentThread();
ThreadGroup mainGroup = main.getThreadGroup();
//System.out.println(threadGroup);
//mainGroup.list();// 将有关此线程组的信息打印到标准输出。
Thread t1 = new Thread(mainGroup,"myThread");
t1.start();
Thread[] arr = new Thread[mainGroup.activeCount()];
main.enumerate(arr);//将线程组中活动的线程复制到指定数组中。
for (Thread thread : arr) {
System.out.println(thread.getName());
}
ThreadGroup parent = mainGroup.getParent();
parent.list();
mainGroup.list();//打印线程组的所有信息
}
}
【运行结果总结】