Java Runnable and Thread
来源:互联网 发布:telnet 端口号不通 编辑:程序博客网 时间:2024/05/17 09:47
I. 简介
线程机制是开发中非常重要、也是非常复杂的一个环节. 那么为什么需要线程?
首先,在程序的执行中,不可避免地会遇到一些需要等待的任务,比如从数据库请求数据、做一些耗时操作等. 而Java 语言本身的任务处理机制是顺序控制流,也就是说,把所有任务排成一个队列,只有第一个任务执行完毕,第二个任务才能执行,第三个任务则要等第二个任务完成…
如果没有多线程的加入,那用户在使用程序时,就只能在某些时候等待一些操作完成,这势必会影响用户体验. 因此,线程的加入,大大地提升了程序的实用性,但同时也增加了程序设计的难度.
II. 线程实质
关于线程需要注意的一点是,即使是在多核处理器上运行,线程机制其实是在单个处理器上交替着完成不同的任务. 比如现在有Task A, Task B 和Task C;这三个任务现在用Java 的多线程机制来解决,情况将会是这样:CPU 给Task A分配了一个小时间块来执行Task A,如果Task A没有完成,那么CPU 现在也会转移到处理Task B上,并给Task B分配同样长度的时间块,并定时切换到处理Task C 去,然后再分给Task C 的时间结束后,再次返回处理Task A,如此循环,直到处理完所有的任务. 但因为CPU 自身的速度够快,会给人一种多个任务在同时执行的错觉.
III. Runnable
介绍完了线程内部的运作方法,下面首先会讲解Runnable 接口.
Runnable 接口自身是不参与线程分配和调度的,它自身的存在目的其实是规定某个线程内的任务要如何执行.
public class Runnables implements Runnable { private int countdown = 5; private int id; public Runnables(int id) { this.id = id; } public String status() { return id + " (" + (countdown > 0 ? countdown: "finished") + "), "; } @Override public void run() { while (--countdown > 0) { System.out.print(status()); } } public static void main(String [] args) { for (int i = 0; i < 5; i++) { Runnables runnables = new Runnables(i); runnables.run(); System.out.println(); } }}
在这个例子中,Runnables 执行了Runnable 接口,并重写了run()
方法;某个task 需要执行的操作,便是写在run()
的.
但由于Runnable 接口本身不具备分发和调用线程的能力,所以所使用的都是同一个线程,即系统分发给main()
函数的线程,并且每个任务都是等上一个任务执行完后再执行的.
而这一点也可以从返回值中看出.
output://0(4), 0(3), 0(2), 0(1), 1(4), 1(3), 1(2), 1(1), 2(4), 2(3), 2(2), 2(1), 3(4), 3(3), 3(2), 3(1), 4(4), 4(3), 4(2), 4(1),
IV. Thread
如果说Runnable 接口是用来规定一个线程中的任务,那么Thread 类便是分发、调度线程的工具了.
在下面的示例中,使用了Thread 来执行 Runnables 类.
public static void main(String [] args) { for (int i = 0; i < 5; i++) { Thread thread = new Thread(new Runnables(i)); thread.start(); System.out.println(); } }
在新建了一个Thread 类对象后,调用start()
方法开始线程. 而每一个线程将会在什么时候运行是无法知道的. 打印台的输出便很好的说明了这一点.
output://0(4), 0(3), 0(2), 0(1), 1(4), 1(3), 1(2), 1(1), 2(4), 2(3), 2(2), 2(1), 3(4), 3(3), 3(2), 3(1), 4(4), 4(3), 4(2), 4(1),
Executor
Executor 能代替开发者管理Thread 对象,从而简化开发过程. 它是客户端与任务执行之间的一个简介层.
public static void main(String [] args) { ExecutorService ex = Executors.newCachedThreadPool(); for (int i = 0; i < 5; i++) ex.execute(new Runnables(i)); ex.shutdown(); }
通过创建Executor 的对象,并调用execute()
方法,就可以启动一个线程了. 而shutdown()
在调用后,将不可通过ex
这个对象创建新的线程了.
同时,这里获得ExecutorService 对象的,是Executors 的方法. 通常会使用newCachedThreadPool()
,但如果需要规定线程数量,可调用newFixedThreadPool()
并传入参数指定线程数,或者调用newSingleThreadExecutor()
返回只能启动一条线程的Executor.
V. Callable
如果需要任务在完成后,返回一个值,就需要使用Callable 而不是Runnable 接口了. Callable 接口需要执行call()
方法,并返回一个值.
public class Callabel implements Callable<String> { private static int count = 0; private int id = ++count; public Callabel() {} @Override public String call() throws Exception { return Integer.toString(id); } public static void main(String [] args) { ExecutorService ex = Executors.newCachedThreadPool(); ArrayList<Future<String>> resutls = new ArrayList<>(); for (int i = 0; i < 5; i++) { resutls.add(ex.submit(new Callabel())); } for (Future<String> result: resutls) { try { // get() blocks until completion System.out.println(result.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } finally { ex.shutdown(); } } }}
这里返回了一个String 对象,并通过类型为Future< String >的数组把结果保存下来了. 也就是说,如果想要获得Callable 返回的数值,需要一个Future 对象来保存,并通过get()
方法来获取值.
VI. Thread 其他方法
TimeUnit sleep() 休眠
使用TimeUnit 的sleep()
方法可以让线程休眠,时间取决于参入的参数.
public class Sleep implements Runnable{ private static int count = 0; private final int id = ++count; @Override public void run() { try { System.out.print(id + "a "); TimeUnit.SECONDS.sleep(2); System.out.print(id + "b "); System.out.println(); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String [] args) { ExecutorService executor = Executors.newCachedThreadPool(); for (int i = 0; i < 5; i++) { executor.execute(new Sleep()); } }}
此处,每个线程会休眠2秒.
Thread.yield() 让步
让步的意思是说:我的任务执行完了,现在我将CPU让步给其他线程.
public class Yield implements Runnable{ private static int count = 0; private final int id = ++count; @Override public void run() { int sum = 0; for (int i = 0; i < 10; i++) { sum += i; if (sum > 10) { System.out.println("id:" + id + " ==> " + sum); Thread.yield(); } } } public static void main(String [] args) { ExecutorService executor = Executors.newCachedThreadPool(); for (int i = 0; i < 5; i++) { executor.execute(new Yield()); } }}output://id:1 ==> 15id:3 ==> 15id:2 ==> 15id:4 ==> 15id:5 ==> 15id:4 ==> 21id:3 ==> 21id:1 ==> 21id:4 ==> 28id:5 ==> 21id:2 ==> 21id:5 ==> 28id:2 ==> 28id:5 ==> 36id:4 ==> 36id:1 ==> 28id:3 ==> 28id:4 ==> 45id:5 ==> 45id:2 ==> 36id:3 ==> 36id:1 ==> 36id:3 ==> 45id:1 ==> 45id:2 ==> 45
每个线程在启动后,开始执行加法运算. 当sum大于10时,线程会暂停当前任务,将CPU 让给下一个线程. 所以从前5个输出中可以看到,线程都是在sum 到达15后暂停的进程.
Thread setPriority() 优先级
尽管各个线程的执行是随机的,但CPU 总会被优先分配给优先级最高的线程执行任务.
public class Priority implements Runnable { private static int count = 0; private final int id = ++count; @Override public void run() { int sum = 0; for (int i = 0; i < 10; i++) { sum += i; if (sum > 10) { System.out.println("id:" + id + " ==> " + sum); Thread.yield(); } } } public static void main(String [] args) { for (int i = 1; i <= 10; i++) { Thread thread = new Thread(new Priority()); thread.setPriority(i); thread.start(); } }}output://id:1 ==> 15id:4 ==> 15id:1 ==> 21id:6 ==> 15id:3 ==> 15id:2 ==> 15id:6 ==> 21id:7 ==> 15id:1 ==> 28id:4 ==> 21id:10 ==> 15id:5 ==> 15id:10 ==> 21id:4 ==> 28id:1 ==> 36id:7 ==> 21id:6 ==> 28id:9 ==> 15id:3 ==> 21id:2 ==> 21id:8 ==> 15id:2 ==> 28id:9 ==> 21id:3 ==> 28id:6 ==> 36id:7 ==> 28id:1 ==> 45id:4 ==> 36id:10 ==> 28id:5 ==> 21id:4 ==> 45id:7 ==> 36id:6 ==> 45id:3 ==> 36id:9 ==> 28id:2 ==> 36id:8 ==> 21id:9 ==> 36id:3 ==> 45id:7 ==> 45id:5 ==> 28id:10 ==> 36id:5 ==> 36id:9 ==> 45id:8 ==> 28id:2 ==> 45id:8 ==> 36id:5 ==> 45id:10 ==> 45id:8 ==> 45
线程优先级按照1 到10排列(与平台有关),1 的优先级最高.
通常在操作平台未知的情况下,会使用Thread.MAX_PRIORITY, Thread.MIN_PRIORITY, 和 Thread.NORM_PRIORITY.
- Java Runnable and Thread
- Thread and Runnable
- java线程的简单例子(Thread and runnable)
- Java Thread Runnable
- Java 线程 Thread Runnable
- java Thread和Runnable
- Java runnable和 thread
- java 线程 thread runnable
- java Thread、Runnable实例
- JAVA多线程:Thread、Runnable
- java Thread 和Runnable区别
- java多线程 Thread 和Runnable
- java 多线程(Thread,Runnable)
- java多线程 Thread 和Runnable
- 记录:java thread Runnable 区别
- java多线程Thread和Runnable
- Thread vs Runnable in Java
- Java多线程Thread与Runnable
- Android wifi解析
- [Java]类的继承学习笔记
- 我的Android进阶之旅------>RxJava学习资料汇总
- 获取浏览器名称和版本号
- 关键代码段(临界区)实现线程死锁
- Java Runnable and Thread
- webpack loader
- 虚继承类内存大小计算
- 拷贝构造函数与赋值构造函数
- SVM核函数
- 2016 UESTC Training for Data Structures B - 卿学姐与基本法 自己构建了一个和堆有点像的数据结构
- 逆置/反转单链表
- yum install lrzsz
- 支付宝的SDK 编译 #include <openssl/asn1.h> not found