多线程
一个线程的生命周期
- 线程是一个动态执行的过程,它也有一个从产生到死亡的过程
-
新建状态
使用new、Thread类或者子类建立一个线程对象后,这个线程处于新建状态。它将一直保持在这个状态直到start() -
就绪状态
当线程对象调用了start()方法之后,线程就进入了就绪状态,处于就绪队列中,等待着jvm虚拟机里面线程调度器的调度 -
运行状态
如果就绪的线程获取到了CPU的资源,那么就能执行run(),此时线程处于运行状态,处于运行状态的线程最为复杂,可以变为阻塞状态、就绪状态、或者死亡状态 -
阻塞状态
如果有一个线程执行了sleep()、suspend()等方法,失去所占用的资源之后,这个线程就会进入阻塞状态。在睡眠时间已到或者获得了设备资源之后就可以重新进入就绪状态
等待阻塞—执行wait()方法,让线程进入到等待阻塞状态
同步阻塞—线程获取到synchronized同步锁失败(被其他线程占用)
其他阻塞—通过调用线程的sleep()或者join()发出了io请求时,线程就会进入到阻塞状态。当sleep()状态超时,join()等待线程终止或者超时,或者io处理完毕,线程重新转入就绪状态。
- 死亡状态
一个运行状态的线程完成任务或者其他终止条件发生的时候,这个线程就切换到终止状态
线程的优先级
- 每一个Java线程都有一个优先级,利于操作系统进行调度
- Java线程的优先级是一个整数,分别为1-10(最大)
- 默认情况下每个进程都会分配一个中等优先级5
- 较高优先级的线程对程序来说更加重要,并且应该优先调度,但是线程不能保证线程执行的顺序,并且非常依赖于平台。
创建线程
- 三种方法
实现Runnable
继承Thread
通过Callable和Future
实现Runnable接口来创建线程
- Runnable接口提供了一个run()方法用于调动其他的一些方法
- 最终还必须通过Thread类来调用自身的线程(类似于Python)
//创建一个实现接口的类
public class multithread implements Runnable {
private String threadName;
private Thread thread;
public multithread(String threadName){
this.threadName = threadName;
}
//如果要实现多线程,这个类必须实现run()方法
public void run(){
for(int i=0;i<20;i++){
System.out.println(this.threadName+" is running!");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println(this.threadName+" exited!");
}
public void start(){
System.out.println("Starting"+this.threadName);
if(thread==null){
//自身新建出一个thread,通过Thread类,通过start()方法来触发
thread = new Thread(this, threadName);
thread.start();
}
}
}
Startingth1
Startingth2
th2 is running!
th1 is running!
th2 is running!
th1 is running!
th2 is running!
th1 is running!
th2 is running!
th1 is running!
进程已结束,退出代码-1
通过继承Thread类来创建线程
- 通过本身的类来继承Thread,然后创建一个该类的实例
- 继承Thread的方式也必须重写run()方法,并且调用start()方法才能执行
public class multithread2 extends Thread{
private Thread t;
private String threadName;
multithread2( String name) {
threadName = name;
System.out.println("Creating " + threadName );
}
public void run() {
System.out.println("Running " + threadName );
try {
for(int i = 4; i > 0; i--) {
System.out.println("Thread: " + threadName + ", " + i);
// 让线程睡眠一会
Thread.sleep(50);
}
}catch (InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println("Thread " + threadName + " exiting.");
}
public void start () {
System.out.println("Starting " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
}
通过Callable和Future创建线程
- 创建 Callable 接口的实现类,并实现 call() 方法,该 call() 方法将作为线程执行体,并且有返回值。
- 创建 Callable 实现类的实例,使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了该 Callable 对象的 call() 方法的返回值。
- 使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线程。
- 调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值。
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CallableThreadTest implements Callable<Integer> {
public static void main(String[] args)
{
CallableThreadTest ctt = new CallableThreadTest();
FutureTask<Integer> ft = new FutureTask<>(ctt);
for(int i = 0;i < 100;i++)
{
System.out.println(Thread.currentThread().getName()+" 的循环变量i的值"+i);
if(i==20)
{
new Thread(ft,"有返回值的线程").start();
}
}
try
{
System.out.println("子线程的返回值:"+ft.get());
} catch (InterruptedException e)
{
e.printStackTrace();
} catch (ExecutionException e)
{
e.printStackTrace();
}
}
@Override
public Integer call() throws Exception
{
int i = 0;
for(;i<100;i++)
{
System.out.println(Thread.currentThread().getName()+" "+i);
}
return i;
}
}