一.继承Thread方式创建多线程
1.创建继承Thread类的子类(该类中的run方法即为要执行的分线程要做的事情)
2.重写子类Thread类中的run方法
3.创建Thread类子类的对象
4.对象调用start()
注意1:不能让子类对象调用run()方法,运行不会报错,但这只是普通的对象调方法,会执行重写的run方法,但不会启动新的线程,run方法中的代码块是在main线程里执行
这就要引入start()方法的作用了:Causes this thread to begin execution; the Java Virtual Machine calls the run method of this thread.
可见,start()方法可以启动新线程并调用run方法,而直接通过对象调用run方法只是调用了run方法,并没有启动新线程。
注意2:对于start(),API文档有这样的说明:It is never legal to start a thread more than once. In particular, a thread may not be restarted once it has completed execution.
意思就是说,一个对象只能调用一次start()方法,调用一次后,再次通过该对象调用start()方法会报错,如下图,如果想再次调用该线程只能重新创建子类对象调用start()方法。
//一:继承Thread方式创建多线程
public class ThreadTest
{
public static void main(String[] args)
{
//3.创建Thread类子类的对象
MultiThread test = new MultiThread();
//4.对象调用start()
test.start();
for(int i = 0;i < 10;i++)
System.out.println("此处执行的线程为:" + Thread.currentThread().getName());
}
}
//1.创建继承Thread类的子类(该类中的run方法即为要执行的分线程要做的事情)
class MultiThread extends Thread
{
//2.重写子类Thread类中的run方法
public void run()
{
for(int i = 0;i < 10;i++)
System.out.println("此处执行的线程为:" + Thread.currentThread().getName());//getName()方法输出当前的对象名
}
}
二.实现Runnable接口的方式创建线程
1.创建实现Runnable接口的类
2.重写run()方法
3.创建实现Runnable接口类的对象。
4.创建Thread类对象并将实现Runnable接口类的对象作为实参参传递到Thread对象的构造器中
5.通过Thread类对象调用start()方法
相对于继承Thread方法创建多线程,用实现Runnable接口的方式创建多线程可以更好的实现多个线程对同一个对象进行操作。
//二.实现Runnable接口的方式创建多线程
public class ThreadTest2 {
public static void main(String[] args)
{
//3.创建实现Runnable接口类的对象。
ThreadTest test = new ThreadTest();
//4.创建Thread类对象并将实现Runnable接口类的对象作为实参参传递到Thread对象的构造器中
Thread thread = new Thread(test);
//5.通过Thread类对象调用start()方法
thread.start();
}
}
//1.创建实现Runnable接口的类
class ThreadTest implements Runnable
{
//2.重写run()方法
public void run()
{
for(int i = 0;i < 10;i++)
System.out.println(Thread.currentThread().getName() + "执行中......");
}
}
三:通过实现Callable接口的方式创建多线程
1.创建一个实现Callable接口的类
2. 重写call()方法
3.创建实现Callable接口的类的对象
4.将创建好的实现Callable接口的类的对象作为实参传到FutureTask类的构造器中
5.将FutureTask类的对象作为实参传递到Thread类的构造器中
6.调用Thread类对象的start()方法
相对于实现Runnable接口,实现Callable接口创建线程的好处是
1.call()可以抛异常,进而捕获异常信息。
2.call()有返回值,返回的值可以供其他线程使用
3.Callable支持泛型。
//三:通过实现Callable接口创建线程
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CallableTest
{
public static void main(String[] args)
{
//3.创建实现Callable接口的类的对象
ThreadTest threadtest = new ThreadTest();
//4.将创建好的实现Callable接口的类的对象作为实参传到FutureTask类的构造器中
FutureTask futureTask = new FutureTask(threadtest);
//5.将FutureTask类的对象作为实参传递到Thread类的构造器中
Thread test = new Thread(futureTask);
//6.调用Thread类对象的start()方法
test.start();
try {
//获取call()方法的返回值
System.out.println("返回的偶数为:" + futureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
//1.创建一个实现Callable接口的类
class ThreadTest implements Callable
{
//2.重写call()方法
public Object call() throws Exception
{
System.out.println("线程名为" + Thread.currentThread().getName() + "的作用是向主线程中返回一个偶数");
while(true)
{
int a = (int)(Math.random() * 100);
if(a % 2 == 0)
return a;
}
}
}
四:通过线程池创建线程(也可以说是把线程方法放进池子里,创建线程的方法依旧是前三种,只不过在这里建了一个池子)
1.创建线程类,此处以实现Runnable接口的方式创建多线程
2.创建线程池,参数为线程池中线程数量。ExecutorService是接口 此处体现了多态,pool的类型为ThreadPoolExecutor,向上转型为ExecutorService
3.创建实现Runnable接口类的对象
4.将实现Runnable接口类的对象作为实参传递到execute()方法中
5.注意最后要关闭线程池
用线程池有许多好处:
例如:
创建指定线程数容量的线程池后,线程创建好后可以实现重复利用(线程用完放回池子,可以减少线程销毁后再次创建线程花费的时间,节省资源)。
可以调用线程池的方法更好的管理线程,比如并发数控制等。
//四:通过线程池创建线程
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPool
{
public static void main(String[] args)
{
//2.创建线程池,参数为线程池中线程数量。ExecutorService是接口 此处体现了多态,pool的类型为ThreadPoolExecutor,向上转型为ExecutorService
ExecutorService pool = Executors.newFixedThreadPool(3);
//3.创建实现Runnable接口类的对象
Threadofpool thread = new Threadofpool();
//4.将实现Runnable接口类的对象作为实参传递到execute()方法中
pool.execute(thread);
//5.注意最后要要关闭线程池
pool.shutdown();
}
}
//1.创建线程类,此处以实现Runnable接口的方式创建
class Threadofpool implements Runnable
{
int i = 0;
public void run() {
for (; i < 5; i++)
{
System.out.println(Thread.currentThread().getName() + "执行中....");
}
}
}