简单使用示例
Java 提供了三种创建线程的方法:
- 通过实现 Runnable 接口;
- 通过继承 Thread 类本身;
- 通过 Callable 和 Future 创建线程。
还有
- 定时器
- 线程池
下面第一个类给出了四种创建方式,第二个类是定时器示例。
①
public class ThreadStartTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.print("主线程(main)0启动!");
//实例化线程对象
Thread_1 thread_1 = new Thread_1();
//调用start()方法开启线程,然后会自动调用run()方法
thread_1.start();
//将实现Runnable接口对象实例化提交给Thread构造器(构造方法)
Thread thread_2 = new Thread(new Thread_2());
thread_2.start();
//callable接口可以返回值,但必须用submit()提交
ExecutorService execu = Executors.newCachedThreadPool();
Future<String> result = execu.submit(new TastWithResult());
System.out.println(result.get());
execu.shutdown();
//线程池
ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(new Thread_2());
exec.shutdown();
//main线程
for(int i=0;i<5;i++) {
//等同于Thread.sleep(2000);
TimeUnit.MILLISECONDS.sleep(2000);
System.out.print("0");
}
}
}
/**
* 继承Thread类,重写run方法
*/
class Thread_1 extends Thread {
@Override
public void run() {
System.out.print("线程1启动!");
for(int i=0;i<5;i++) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.print("1");
}
}
}
/**
* 实现Runnable接口
*/
class Thread_2 implements Runnable{
@Override
public void run() {
System.out.print("线程2启动!");
for(int i=0;i<5;i++) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.print("2");
}
}
}
class TastWithResult implements Callable<String> {
@Override
public String call() throws Exception {
return "可以返回值啦!";
}
}
②定时器Timer
public class TimerTest {
public static void main(String[] args) throws InterruptedException {
Timer timer = new Timer();
//前一次执行程序结束后 2000ms 后开始执行下一次程序(循环)
timer.schedule(new TimerTask(){
@Override
public void run(){
System.out.println("Task1");
}
},0,2000);
//延迟1000ms执行程序
timer.schedule(new TimerTask(){
@Override
public void run(){
System.out.println("Task2");
}
},1000);
//前一次程序执行开始 后 2000ms后开始执行下一次程序(循环)
timer.scheduleAtFixedRate(new TimerTask(){
@Override
public void run(){
System.out.println("Task3");
}
},0,2000);
Thread.sleep(10*1000);
timer.cancel();
}
}
如果你想详细的了解一下Timer内部实现,可以参考下面的文章
说明
在《阿里巴巴java开发手册中》有这样一条:
3. 【强制】线程资源必须通过线程池提供,不允许在应用中自行显式创建线程。
说明:使用线程池的好处是减少在创建和销毁线程上所消耗的时间以及系统资源的开销,解决资源不足的问题。如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗完内存或
者“过度切换”的问题。
所以建议使用线程池。
4. 【强制】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样
的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
说明:Executors 返回的线程池对象的弊端如下:
1)FixedThreadPool 和 SingleThreadPool:
允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
2)CachedThreadPool 和 ScheduledThreadPool:
允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。
又因为有该建议,所以需要对线程池稍微深入了解使用。可以参考下面这篇文章。