Java并发控制基础篇 Thread继承类和Runnable实现类

来源:互联网 发布:java web直播开源系统 编辑:程序博客网 时间:2024/06/10 01:02

     

更多面试题请狠狠的点击 下载

 在我们面试的过程中常常会碰到多线程的问题,对于多线程的实现方式主要有两种:实现Runnable接口、继承Thread类。对于这两种多线程的实现方式也是有着一些差异。既然实现了多线程那必然离不开管理这些线程,当问题比简单时一个或者几个线程就OK了,也涉及不到效率问题。一旦线程数量多起来的时候,必然躲不过这些线程的创建与销毁,而往往这是很浪费时间的。这时就需要利用线程池来进行管理,既免去了我们创建线程和销毁线程的代码,也提高了程序的效率。下面针对以上问题做出相关讲解。

一、Runnable、Thread比较

首先阐述实现Runnable的好处:

  • java不允许多继承,因此实现了Runnable接口的类可以再继承其他类。
  • 方便资源共享,即可以共享一个对象实例???(从很多博客中看到这样描述,但是此处有疑问,例子如下)

下面来通过具体代码来解释上述优点,网上很流行的买票系统,假设有5张票,首先通Thread来进行购买。代码如下:

一:通过继承Thread类来实现买票

public class OwnThread extends Thread{private int ticket=5;//票数5private String name;public OwnThread(String name) {this.name=name;}public void run() {for(int i=1;i<=5;i++){if(ticket>0)System.out.println(this.name+",卖票:"+this.ticket--);}}}
测试类:

public class TestThread {public static void main(String[] args) {Thread t1=new OwnThread("张大锤");Thread t2=new OwnThread("方进钟");t1.start();t2.start();}}

效果如图:

二。实现Runnable接口

public class MyThread implements Runnable {private int ticket=5;//利用火车卖票public void run() {for(int i=1;i<=5;i++){if(ticket>0)System.out.println(Thread.currentThread().getName()+",卖票了:"+ticket--);}}}
测试类

public class TestThread {public static void main(String[] args) {Runnable r=new MyThread();Thread t1=new Thread(r,"张大锤");Thread t2=new Thread(r,"方进钟");t1.start();t2.start();}}
效果图:


Runnable和Thread区别

实际开发中我们通常采用Runnable接口来实现多线程。因为实现Runnable接口比继承Thread类有如下好处: 
1. 避免继承的局限,一个类可以继承多个接口,但是类只能继承一个类。 
2. Runnable接口实现的线程便于资源共享。而通过Thread类实现,各自线程的资源是独立的,不方便共享。上面例2可以看出线程a跟线程b各卖了5张票,而例子3两个线程共卖了5张票,而且没有重复

二、线程池

创建线程池主要有三个静态方法供我们使用,由Executors来进行创建相应的线程池:

public static ExecutorSevice newSingleThreadExecutor()public static ExecutorSevice newFixedThreadPool(int nThreads)public static ExecutorSevice newCachedThreadPool()public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4
  • newSingleThreadExecutor返回以个包含单线程的Executor,将多个任务交给此Exector时,这个线程处理完一个任务后接着处理下一个任务,若该线程出现异常,将会有一个新的线程来替代。
  • newFixedThreadPool返回一个包含指定数目线程的线程池,如果任务数量多于线程数量,那么没有执行的任务必须等待,直到有任务完成为止。
  • newCachedThreadPool根据用户的任务数创建相应的线程来处理,该线程池不会对线程数目加以限制,完全依赖于JVM能创建线程的数量,可能引起内存不足。
  • newScheduledThreadPool创建一个至少有n个线程空间大小的线程池。此线程池支持定时以及周期性执行任务的需求。

我们只需要把实现了Runnable的类的对象实例放入线程池,那么线程池就自动维护线程的启动、运行、销毁。我们不需要自行调用start()方法来开启这个线程。线程放入线程池之后会处于等待状态直到有足够空间时会唤醒这个线程。

private ExecutorService threadPool = Executors.newFixedThreadPool(5);threadPool.execute(socketThread);//至少维护5个线程容量的空间private ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(5);//函数意义:一个线程开始之后和下一个线程开始的时间间隔//第一个时间参数表示初始化执行延迟1000毫秒,第二个时间参数表示每隔1000毫秒执行一次//第二个线程必须等到第一个线程执行完成才能继续执行,尽管时间间隔小于线程执行时间threadPool.scheduleAtFixedRate(socketThread, 1000, 1000, TimeUnit.MILLISECONDS);//基本参数和上面的类似,函数意义不一样:一个线程结束之后和下一个线程开始的时间间隔threadPool.scheduleWithFixedDelay(socketThread, 1000, 1000, TimeUnit.MILLISECONDS);//线程池不接收新加的线程,但是执行完线程池内部的所有线程threadPool.shutdown();//立即关闭线程池,停止线程池内还未执行的线程并且返回一个未执行的线程池列表threadPool.shutdownNow();

阅读全文
0 0
原创粉丝点击