生成线程的几种方式,以及他们的区别

生成线程的方式分别为:

(1)继承Thread类

(2)实现Runnable接口

(3)实现Callable接口,通过Future得到线程执行信息

(4)通过线程池创建线程

1)通过继承Thread类实现对象

优点:

Thread类实现了Runnable接口,编写简单,如果需要访问当前线程,可以通过this获得

缺点:

java是单继承机制,扩展性降低

备注:

Synchronized如果锁的位置是方法上,锁的是当前传入的实例对象,如果是同步代码块上锁的是括号中配置的对象,可以是this当前实例对象,也可以是class对象,如果锁的是静态代码块,静态同步方法,锁的是当前类的class对象

public class ThreadTest{

    public static void main(String[] args) {
        MyThread myThread1 = new MyThread();
        MyThread myThread2 = new MyThread();
        MyThread myThread3 = new MyThread();
        myThread1.start();
        myThread2.start();
        myThread3.start();
    }

}
class MyThread extends Thread{
    @Override
    public void run() {
        synchronized (MyThread.class){
            try {
                for(int i=0;i<10;i++){
                    System.out.println("i = "+i);
                }
                System.out.println(this.getName()+"---------"+this.getClass());
            }catch (Exception e){
                System.out.println(e.getMessage());
            }
        }
    }
}

2)实现Runnable接口

Runnable接口信息,只有一个无返回类型的润抽象方法

Runnable任务中的run无返回值,run方法不可以抛出异常

public class ThreadTest {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        Thread thread0 = new Thread(myThread);
        Thread thread1 = new Thread(myThread);
        Thread thread2 = new Thread(myThread);
        thread0.start();
        thread1.start();
        thread2.start();
    }
}
class MyThread implements Runnable{
    @Override
    public void run() {
        synchronized (this){
            System.out.println(this);
            for(int i=0;i<10;i++){
                System.out.println("i ="+i);
            }
            System.out.println(Thread.currentThread().getName());
        }
    }
}

3)实现callable接口

Callable接口可以有返回值,返回值必须有Future对象去接收,其可以抛出异常,根据接口信息也可以看出,可以通过FutureTask的get方法得到子线程的最终运行结果

public class ThreadTest {
    public static void main(String[] args) {
       FutureTask<Integer> task = new FutureTask<>(new Callable<Integer>() {
           private int i = 0;
           @Override
           public Integer call() throws Exception {
               for(;i<10;i++){
                   System.out.println("i = "+i+"------"+Thread.currentThread().getName());
               }
               return i;
           }
       }) ;

       for(int i=0;i<10;i++){
           System.out.println(Thread.currentThread().getName()+"==="+i);
           if(i==2){
               Thread thread = new Thread(task,"的线程有返回值");
               thread.start();
           }
       }
       try {
           System.out.println("call线程返回的最终值为:"+task.get());
       }catch (Exception e){
           System.out.println(e.getMessage());
       }
    }
}

4)通过线程池创建线程

线程池创建线程的方法有很多种,jdk自带的Executors也可以创建线程,但Executors有如下弊端(参考于阿里开发手册):

1)FixedThreadPool和SingleThreadPool

允许请求的队列长度近乎无限大,可能堆积大量请求,导致oom

2)CacheThreadPool和ScheduleThreadPool

允许创建的线程数近乎无限大,可能会创建大量线程,导致oom

ThreadPoolExecutor参数为线程池大小,最大线程池容量,存活时间,队列容量大小,一旦提交的线程数超过当前可用线程数,会抛出拒绝执行异常,原因是有界队列满了便无法处理新的任务。

public class ThreadTest {
    public static void main(String[] args) {
        ExecutorService executorService = new ThreadPoolExecutor(
                5,5,10,TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(5));
        for(int i=0;i<10;i++){
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"运行线程池任务");
                }
            });
        }
    }
}
发布了18 篇原创文章 · 获赞 0 · 访问量 2156

猜你喜欢

转载自blog.csdn.net/weixin_42163781/article/details/104940072