Java并发编程之多线程实现方法

Java实现多线程的方式有比较多,但究其本质,最终都是在执行Thread的run方法,这个后文再作解释。下面先看看各种实现方式。

实现 Runnable 接口

public class RunnableThread  implements Runnable{
    @Override
    public void run() {
        System.out.println("Runnable接口实现线程");
    }
​
    public static void main(String[] args) {
        new Thread(new RunnableThread()).start();
    }
}

通过实现 Runnable 接口实现多线程,只需要重写run接口,然后将Runnable实例传递给Thread类,调用start即可启动线程。

继承 Thread 类

public class ExtendsThread extends Thread {
​
    @Override
    public void run() {
        System.out.println("用Thread类实现线程");
    }
​
    public static void main(String[] args) {
        new ExtendsThread().start();
    }
}

继承 Thread 类实现多线程,这种方式直接重写Thread类的run方法,同样通过start方法启动多线程。

线程池创建线程

还可以通过线程池创建线程,方式参考如下

/**
 * @author kangming.ning
 * @date 2023-02-24 16:27
 * @since 1.0
 **/
public class CustomThreadPool1 {
 
    private static ThreadFactory threadFactory = new ThreadFactoryBuilder().setNamePrefix("线程池-").build();
 
    private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
            Runtime.getRuntime().availableProcessors(),
            Runtime.getRuntime().availableProcessors() * 2,
            60L,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(10),
            threadFactory, new ThreadPoolExecutor.CallerRunsPolicy());
 
    public static void main(String[] args) throws InterruptedException {
        Runnable r = () -> {
            System.out.println(Thread.currentThread().getName() + " is running");
        };
        for (int i = 0; i < 35; i++) {
            Thread.sleep(1000);
            threadPoolExecutor.submit(r);
        }
    }
 
}

当然,也可以使用ExecutorService去管理线程池,这个方式和上面的没本质区别,ExecutorService实际也是使用ThreadPoolExecutor创建的线程池,如下:

public class FixedThreadPool {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
        for (int i = 0; i < 5; i++) {
            executor.execute(new RunnableThread());
        }
        executor.shutdown();
    }
}

public class RunnableThread implements Runnable {
    @Override
    public void run() {
        System.out.println("用实现Runnable接口实现线程,ThreadName:" + Thread.currentThread().getName());
    }
}

有返回值的 Callable 创建线程

public class CallableTask implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        return new Random().nextInt();
    }
​
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //创建线程池
        ExecutorService service = Executors.newFixedThreadPool(10);
        //提交任务,并用Future提交返回结果
        Future<Integer> future = service.submit(new CallableTask());
        Integer randomNumber = future.get();//此方法阻塞
        System.out.println("randomNumber:"+randomNumber);
        service.shutdown();
    }
}

定时器 Timer

public class TimerTest {
    public static void main(String[] args) {
        Timer timer=new Timer();
        //延时0毫秒 每1秒执行一次
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("Timer线程,ThreadName:"+Thread.currentThread().getName());
            }
        },0,1000);
    }
}
定时器Timer内部使用TimerThread处理定时任务,TimerThread继承于Thread类,于是,还是之前方式,只是包装了一下。

线程实现原理源码探索

通过上面的讲述,我们发现,看似有很多方式去实现多线程,但最终都需要通过Thread类,调用start方法,实现线程的开启。下面看一下Thread类的start方法

 /* What will be run. */
 private Runnable target;
 
 public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
​
        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        group.add(this);
​
        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }
    
    private native void start0();
 
     @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }

可以看出,start方法最终会经由start0本地方法最终调用run方法。而run方法里面的target是一个Runnable对象,如果target不是空,就调用target的run方法。这就解释了为什么实现Runnable接口传递给Thread构造函数,最终能调用Runnable的run方法。如果我们用继承Thread重写run方法来实现线程,明显,start方法调用的run方法直接就是这个子类的run方法了。这样看来,实现多线程只有一种方法,就是构造Thread类,调用start方法,经由本地方法start0最终调用它的run方法。

实现 Runnable 接口方式比继承 Thread 类方式好的理由

  • Runnable 与 Thread 类的解耦,Thread 类负责线程启动和属性设置等内容,Runnable负责跑任务
  • 可扩展 性更强,Java 语言不支持双继承,实现Runnable接口的类未来还可以继承别的类
  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值