文章目录
一、多线程实现方式
1.1 无返回值
1.1.1 继承Thread类
代码如下(示例):
public class TheadDemo extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(super.getName() + "==>" + i);
}
}
public static void main(String[] args) {
new TheadDemo().start();
new TheadDemo().start();
}
}
1.1.2 实现Runnable接口
代码如下(示例):
public class RunnableDemo implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"==>"+i);
}
}
public static void main(String[] args) {
RunnableDemo runnableDemo=new RunnableDemo();
new Thread(runnableDemo).start();
new Thread(runnableDemo).start();
}
}
1.1.3 二者的优缺点
- Java使用的是单继承,所以使用继承Thread类来实现多线程会无法继承其他类
- 使用继承方式实现线程,在启动线程时需要new一个线程的实现类,导致无法实现资源共享
- 使用继承方式可以直接使用Thread的一些方法,有些时候会更简便些
- 这两种方法在运行中都没有返回值,若需要返回值或在线程运行中需要取消线程可以考虑下面介绍的 Callable接口
启动线程请调用start()方法,而不是调用run()方法
在需要共享资源时常常使用锁来防止多消费等问题
1.2. 有返回值Callable
1.2.1 Callable简单使用
代码如下(示例):
public class CallableDemo implements Callable<Integer> {
@Override
public Integer call() throws Exception {
Thread.sleep(1000);
return 4343;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executor = Executors.newCachedThreadPool();
CallableDemo task = new CallableDemo();
Future<Integer> result = executor.submit(task);
// 注意调用get方法会阻塞当前线程,直到得到结果。
// 所以实际编码中建议使用可以设置超时时间的重载get方法。
System.out.println(result.get());
executor.shutdown();
}
}
1.2.2 Future接口常用方法介绍
代码如下(示例):
//尝试取消一个线程的执行,不一定会成功。例如线程已执行完成、线程已取消、或其他因素导致取消失败。
boolean cancel(boolean mayInterruptIfRunning);
// 线程是否已取消
boolean isCancelled();
// 线程是否已结束
boolean isDone();
// 获取返回值
V get() throws InterruptedException, ExecutionException;
// 在规定时间内获取返回值,若在时间内没获取到则报错
V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
二、线程组与线程优先级的设置
2.1 线程组
在Java中线程是存在于线程组中的,如果你在创建线程时没有指定线程组,那么系统会将你分配到父线程所在的线程组上
代码如下(示例):
public static void main(String[] args) {
Thread testThread = new Thread(() -> {
System.out.println("testThread当前线程组名字:" +
Thread.currentThread().getThreadGroup().getName());
System.out.println("testThread线程名字:" +
Thread.currentThread().getName());
});
testThread.start();
System.out.println("执行main所在线程的线程组名字: " + Thread.currentThread().getThreadGroup().getName());
ystem.out.println("执行main方法线程名字:" + Thread.currentThread().getName());
}
运行结果:
执行main所在线程的线程组名字: main
testThread当前线程组名字:main
执行main方法线程名字:main
testThread线程名字:Thread-0
2.2 线程优先级设置
- 在Java中线程优先级分为1-10 ,默认为5,优先级越高越有可能抢到资源,获得交配权。
- 使用Thread类的setPriority()来设置线程的优先级
注:并非优先级越高就越先执行,设置优先级就像是设置抽奖一样(当然不是腾讯的那种抽奖),优先级高的先执行的可能性比较大一点而已。并且最终解释权在操作系统手里。
三、线程的六种状态与转态之间的转换
3.1 线程的状态
public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
}
- NEW: 新建状态,在创建完线程但未执行start() 方法前,线程属于 新建状态,在创建完线程但未执行start()方法
- RUNNABLE:运行状态,Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。
线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行中状态(running) - BLOCKED:阻塞状态,线程在等待锁的释放时的状态
- WAITING:等待状态,等待其他线程唤醒
- TIMED_WAITING:超时等待状态,与WAITING不同,TIMED_WAITING在时间到的时候可以自己唤醒自己
- TERMINATED:终止状态,线程已经执行完毕了
3.2 线程状态转化图
总结
提示:以上内容参考于 深入浅出Java多线程