java多线程学习二
来源:互联网 发布:数控旋压机编程 编辑:程序博客网 时间:2024/06/05 11:06
运行线程
目前在java的线程学习中,我学到的创建、运行线程的方法主要有三种。
方法一、第一种是直接构造Thread类的一个实例,调用它的start()方法。要让线程完成一些操作,可以对Thread类派生子类,覆盖其run()方法。
下面的例子源于书本,该程序用于计算多个文件的安全散列算法(SHA)的摘要。 DigestThread是Thread的子类,它的run()方法为指定文件计算一个256位的
SHA-2消息摘要。为此要用一个DigestInputStream来读取这个文件。读取结束时,可以从digest()方法种得到这个散列。
例子一:
package com.HL.DigestThread;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;import java.security.DigestInputStream;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import javax.swing.filechooser.FileNameExtensionFilter;import javax.xml.bind.DatatypeConverter;import javax.xml.bind.DatatypeConverterInterface;public class DigestThread extends Thread{private String fileName;public DigestThread(String fileName){this.fileName = fileName;}@Overridepublic void run() {// TODO Auto-generated method stubtry {FileInputStream inputStream = new FileInputStream(fileName);try {MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");DigestInputStream digestInputStream = new DigestInputStream(inputStream, messageDigest);try {while(digestInputStream.read() != -1);digestInputStream.close();byte[]digest = messageDigest.digest();StringBuilder result = new StringBuilder(fileName);result.append(":");result.append(DatatypeConverter.printHexBinary(digest));System.out.println(result);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}} catch (NoSuchAlgorithmException e) {// TODO Auto-generated catch blocke.printStackTrace();}} catch (FileNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}super.run();}public static void main(String[] args) {for(String filename :args){Thread t = new DigestThread(filename);t.start();}}}main()方法从命令行中读取文件名,针对每个文件名启动一个新的DigestThread。
注意,这里Thread的派生子类,只应当覆盖run()方法,而不应该覆盖其它方法,例如start(),join()等标准方法。
方法二、为了避免覆盖Thread的标准方法,推荐编写一个Runnable的实例,将线程需要 完成的任务包装在run()中。
第二个例子将第一个例子改写使用了runnable接口,把extends Thread改为了implements Runnable,并在main()方法里把DigestRunnable对象传给了Thread的
构造函数,程序的基本逻辑没有改变。
例子二:
package com.HL.DigestThread;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;import java.security.DigestInputStream;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import javax.swing.filechooser.FileNameExtensionFilter;import javax.xml.bind.DatatypeConverter;import javax.xml.bind.DatatypeConverterInterface;public class DigestThreadRunnable implements Runnable{private String fileName;public DigestThreadRunnable(String fileName){this.fileName = fileName;}@Overridepublic void run() {// TODO Auto-generated method stubtry {FileInputStream inputStream = new FileInputStream(fileName);try {MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");DigestInputStream digestInputStream = new DigestInputStream(inputStream, messageDigest);try {while(digestInputStream.read() != -1);digestInputStream.close();byte[]digest = messageDigest.digest();StringBuilder result = new StringBuilder(fileName);result.append(":");result.append(DatatypeConverter.printHexBinary(digest));System.out.println(result);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}} catch (NoSuchAlgorithmException e) {// TODO Auto-generated catch blocke.printStackTrace();}} catch (FileNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}super.run();}public static void main(String[] args) {for(String filename :args){DigestThreadRunnable dr = new DigestThreadRunnable(filename);Thread thread = new Thread(dr);thread.start();}}}
方法三:Executor和callable创建线程。这里涉及到一个知识点,如何从线程返回信息,这是多线程编程中最常被误解的方面之一。run()和start()方法本身不返回任何值,,大多数人的第一个反应是把结果存储在一个字段中,再提供一个获取方法,如下面的例子所示。
public byte[] getDigest() {return digest;}
在主程序中使用存取方法取得线程输出
package com.HL.DigestThread;import javax.xml.bind.DatatypeConverter;public class ReturnDigestTest {public static void main(String[] args) {for(String fileName : args){DigestThread dt = new DigestThread(fileName);dt.start();//显示结果StringBuilder result = new StringBuilder(fileName);result.append(":");byte[]digest = dt.getDigest();result.append(DatatypeConverter.printHexBinary(digest));System.out.println(result);}}}
但这样做是存在问题的,我们可能得不到正确的输出。因为dt.start()启动的计算可能在dt.getDigest()之前还没有结束,也可能结束了,主线程是不会等子线程的。如果还没有结束,dt.getDigest()则会返回null,此时访问digest会抛出异常。
Java5 引入了多线程编程的一个新方法,通过隐藏细节可以更容易的处理回调。我们不再需要直接创建一个线程,是需要创建一个ExecutorService,它会根据你的需要创建线程,可以向ExecutorService提交Callable任务,对于每个Callable任务,会分别得到一个Future,之后可以向Future请求得到任务的结果。
下面这个例子,用于找出一个数字数组中的最大值,将一个任务分配到了两个线程中运行,这样比单线程运行快不少。
例子二:
package com.HL.callableTest;import java.util.concurrent.Callable;public class FindMaxTask implements Callable<Integer>{private int[]data;private int start;private int end;public FindMaxTask(int[]data,int start,int end ) {// TODO Auto-generated constructor stubthis.data = data;this.start = start;this.end = end;}@Overridepublic Integer call() throws Exception {// TODO Auto-generated method stubint max = Integer.MIN_VALUE;for(int i = start; i < end; i++){if(data[i] > max) max = data[i];}return max;}}
package com.HL.callableTest;import java.util.concurrent.ExecutionException;import java.util.concurrent.Executor;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;public class ThreadMaxFinder {public static int max(int[]data) throws InterruptedException, ExecutionException {if(data.length == 1)return data[0];FindMaxTask task1 = new FindMaxTask(data, 0, data.length/2);FindMaxTask task2 = new FindMaxTask(data, data.length/2, data.length);//创建两个线程ExecutorService service = Executors.newFixedThreadPool(2);Future<Integer> future1 = service.submit(task1);Future<Integer> future2 = service.submit(task2);return Math.max(future1.get(), future2.get());}public static void main(String[] args) {try {System.out.println(String.valueOf(max(new int[]{12,5,16})));} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (ExecutionException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}
在最后一句Math.max(future1.get(), future2.get())中,调用future1.get()时,这个方法会阻塞,只有当第一个FindMaxTask结束时,才会调用future2.get()。一旦两个线程都结束,将比较它们的结果,并返回最大值。
0 0
- java多线程学习二
- java多线程学习二
- Java多线程学习笔记(二)
- 学习笔记二:java多线程
- java多线程学习(二)
- Java 多线程编程学习(二)
- java多线程学习(二)
- java多线程学习(二)
- java多线程学习(二)
- java多线程学习(二)
- 【JAVA学习】(二)JAVA 多线程同步
- 学习JAVA多线程程序设计(二)
- Java多线程学习总结(二)
- Java多线程学习总结(二)
- java学习笔记(二)多线程
- java之学习多线程(二)
- java多线程入门学习(二)
- Java多线程学习笔记(二)
- IE下响应304
- Object.GetType()到底是怎么工作的
- CSS中样式命名tips
- django遇到TypeError: can't multiply sequence by non-int of type 'tuple'
- python之装饰器decorator
- java多线程学习二
- Spark Job调优(Part 1)
- HashMap Hashtable区别
- hadoop第三坑
- 00003 不思议迷宫.0009.4:攻防计算
- 博世传感器调试笔记(一)----加速度传感器BMA253
- HashMap与ConcurrentHashMap的区别
- bzoj3204[SDOI2013]城市规划
- 设置jdk环境变量-超详细版
原创粉丝点击
热门IT博客
热门问题
老师的惩罚
人脸识别
我在镇武司摸鱼那些年
重生之率土为王
我在大康的咸鱼生活
盘龙之生命进化
天生仙种
凡人之先天五行
春回大明朝
姑娘不必设防,我是瞎子
狗熊照片
大狗熊图片
狗熊天赋
狗熊英文
狗熊英语
小狗熊
狗熊打野
两只笨狗熊故事
泡个狗熊相公
给狗熊奶奶读信
梦见狗熊是什么预兆
狗熊毛绒玩具
狗熊保护动物
你和狗熊站在一起打一动物
大狗熊毛绒玩具
我们要去捉狗熊
梦见狗熊追我什么意思
猴子狗熊和狐狸
大欺小的狗熊
毛绒玩具狗熊
梦见狗熊是什么意思
以大欺小的狗熊故事
两只笨狗熊的故事
狗熊是什么意思
黑熊图片
马来熊
太阳熊
黑熊
幼儿故事两只笨狗熊
寓言故事两只笨狗熊
狗爷
91狗爷
都市之春光无限 狗爷
狗牌
狗牌图片
哈狗杭牌三合一
亮狗牌
狗牌寄语创意简短
狗牌回家搞笑寄语大全
狗牌定制
2018狗牌寄语简短