继承 Thread 类创建线程类
public class MyThread extends Thread{
int i=0;
public void run(){
for(;i<10;i++){
System.out.println(getName()+" "+i);
}
}
public static void main(String[] args){
// 无参数构造器,调用自身的资源,资源不能共享
new MyThread().start();
new MyThread().start();
}
}
输出结果:
Thread-1 0
Thread-1 1
Thread-1 2
Thread-1 3
Thread-1 4
Thread-1 5
Thread-1 6
Thread-0 1
Thread-0 2
Thread-0 3
Thread-0 4
Thread-0 5
Thread-0 6
Thread-0 7
Thread-0 8
Thread-1 7
Thread-1 8
Thread-1 9
Thread-0 9
要用 start() 方法启动线程,不能直接调用 run() 方法,直接调用 run() 方法就是普通的方法调用,而不是启动线程。
别的文章都说继承 Thread 类不能实现资源共享,那是因为他们启动的两个线程本身就是使用不同的资源,上面的代码就是使用不同的资源,下面实现一个使用同一个资源的 Thread 类
class Integer {
public int num;
public Integer(int num){
this.num=num;
}
}
class MyThread extends Thread {
Integer a;
public MyThread(Integer b){
a=b;
}
public void run(){
for(;a.num<10;){
a.num++;
System.out.println(getName()+" "+a.num);
}
}
public static void main(String[] args){
Integer num=new Integer(0);
// 使用带参数的构造器,调用同一个资源,实现资源共享
new MyThread(num).start();
new MyThread(num).start();
}
}
输出结果:
Thread-0 1
Thread-0 2
Thread-0 3
Thread-1 4
Thread-0 5
Thread-1 6
Thread-0 7
Thread-1 8
Thread-0 9
Thread-1 10
实现Runnable接口创建线程类
public class MyRunnable implements Runnable {
int i=0;
public void run(){
for(;i<10;i++){
System.out.println(getName()+" "+i);
}
}
public static void main(String[] args){
MyRunnable t = new MyRunnable () ;
// 带参数构造器,调用同一个 Runnable 对象,实现资源共享
new Thread(t).start();
new Thread(t).start();
}
}
输出结果:
Thread-1 0
Thread-0 0
Thread-1 1
Thread-0 2
Thread-1 3
Thread-0 4
Thread-1 5
Thread-0 6
Thread-1 7
Thread-0 8
Thread-1 9
实现Callable接口创建线程类
// Callable 接口提供了 call() 方法作为线程执行体,该方法有返回值,可以抛出异常
public class MyCallable implements Callable<String>{
public String call(){
System.out.println(Thread.currentThread().getName());
return "线程执行结束";
}
public static void main(String[] args){
MyCallable t=new MyCallable();
// 使用 FutureTask 来包装 Callable 对象,该类可以获得 call() 方法的返回值
FutureTask<String> task=new FutureTask<String>(t);
//实质还是以 Callable 对象来创建线程
new Thread(task).start();
try {
// 获取线程返回值,主线程进入阻塞状态,直到子线程结束后得到返回值
System.out.println(task.get());
} catch (Exception e) {
e.printStackTrace();
}
}
}
使用线程池管理线程
启动一个新线程的成本是比较高的,如果需要创建大量生命期很短的线程时,就使用线程池。
线程池在启动时即创建大量空闲的线程,程序将一个Runnable对象传给线程池,线程池就启动一条线程来执行该对象的 run() 方法,当 run() 方法执行结束后,该线程并不会死亡,而是再次返回线程池中成为空闲状态,等待下一个对象。
Executors类提供了5种线程池
newCachedThreadPool ()
创建一个具有缓存功能的线程池,若当前没有可用线程,就创建一个新的线程缓存到池中,若线程长时间(默认60秒)未被使用,则终止该线程。
newFixedThreadPool (int nThreads)
创建一个固定线程数的线程池,超出的线程会在队列中等待。
newSingleThreadExecutor ()
创建一个单线程的线程池,即线程顺序执行。
newScheduledThreadPool (int corePoolSize)
创建具有指定线程数的线程池,它可以在指定延迟后执行线程任务。
newSingleThreadScheduledExecutor ()
创建一个单线程的线程池,它可以在指定延迟后执行线程任务。
前三个方法返回 ExcutorService 对象,使用 submit() 或 execute() 方法提交线程任务
后两个方法返回 ScheduledExecutorService 对象,使用 schedule() 方法提交线程任务
线程任务可以是 Runnable 对象或 Callable 对象
// execute() 方法没有返回值,只能提交 Runnable 对象
Executors.newFixedThreadPool (6).execute (new Runnable () {
public void run () {
System.out. println (Thread.currentThread().getName () ) ;
}
}) ;
// submit() 方法有返回值,提交 Runnable 对象时返回值为 null
Executors.newSingleThreadExecutor ().submit (new Runnable () {
public void run () {
System.out. println (Thread.currentThread().getName () ) ;
}
}) ;
// submit() 方法可以返回 Callable 对象的返回值
Future<String> f=Executors.newCachedThreadPool ().submit (new Callable<String> () {
public String call () {
System.out. println (Thread.currentThread().getName () ) ;
return "线程执行结束";
}
}) ;
// schedule() 方法提交指定延迟的线程任务,可以作用在 Runnable 对象和 Callable 对象,Runnable 对象的返回值是 null
Executors.newScheduledThreadPool (6).schedule (new Runnable () {
public void run () {
System.out. println (Thread.currentThread().getName () ) ;
}
//延迟3秒执行
}, 3, TimeUnit.SECONDS) ;
// scheduleAtFixedRate() 方法类似 schedule(),只是scheduleAtFixedRate() 方法可以设定线程重复执行的频率
Executors.newScheduledThreadPool (6).scheduleAtFixedRate (new Runnable () {
public void run () {
System.out. println (Thread.currentThread().getName () ) ;
}
//延迟3秒执行,每2秒执行一次
}, 3, 2, TimeUnit.SECONDS) ;