Java多线程学习(二)

一、定义产生返回值的任务

在上一篇文的介绍中,我们知道了定义任务通常的方法是定义一个实现Runnable接口的类,这个类被我们成为任务。然而也很容易注意到,任务的最重要的一个方法就是run( )方法,而run( )方法是没有返回值的,也就是说我们之前定义的任务不返回任何值。

如果想要定义一个有返回值的任务,则需要编写一个实现Callable接口的类。Callable是一种具有类型参数的泛型,他的类型参数表示的是call( )方法的返回值类型。

示例如下:

 1 import java.util.concurrent.Callable;
 2 import java.util.concurrent.ExecutionException;
 3 import java.util.concurrent.ExecutorService;
 4 import java.util.concurrent.Executors;
 5 import java.util.concurrent.Future;
 6
 7 /**
 8  * @author Gao
 9  * Date:2016.5
10  * */
11
12 class Task implements Callable<String> {
13     int testNum;
14     public Task(int testNum) {
15         this.testNum = testNum;
16     }
17     public String call() {
18         return "Test number is " + testNum;
19     }
20 }
21
22 public class ReturnedDemo {
23     public static void main(String[] args) {
24         //创建ExecutorService的实例化对象,用来执行任务。
25         ExecutorService exec = Executors.newCachedThreadPool();
26         Future<String> future = exec.submit(new Task(123));
27         try {
28
29             System.out.println(future.get());
30         } catch (InterruptedException e) {
31             // TODO 自动生成的 catch 块
32             e.printStackTrace();
33         } catch (ExecutionException e) {
34             // TODO 自动生成的 catch 块
35             e.printStackTrace();
36         }
37
38     }
39 }
40 /*Output:
41 Test number is 123
42 */

在上面的示例代码中你可能会不了解Future<T>的含义。ExecutorService类的实例化对象在调用submit( )方法时会返回Future<T>类型的返回值,我们在这里实例化的future对象用来保存该返回值,在之后用来处理和其他过程。同时,在调用get( )方法时会产生异常,所以该段用try-catch块进行包围。

二、线程的优先级与让步

1.线程的优先级

线程由线程调度器调用执行,线程调度器进行线程调度的时候倾向于让优先级高的线程先运行。但是由于CPU处理线程集的顺序是不固定的,因此线程调度器只是起到一个“建议”的作用,而不是决定性作用。同时,线程优先级只是代表线程集中的线程执行的频率。高优先级的线程执行的频率较高,但是低优先级的线程也会得到执行。

由于不同操作系统的优先级不同且和JDK的优先级不同(JDK有10个优先级),所以JDK和操作系统优先级的映射不是很好。通常我们在调整优先级的时候,仅仅使用MAX_PRIORITY、NORM_PRIORITY、MIN_PRIORITY三种级别。

示例代码如下:

 1 import java.util.concurrent.ExecutorService;
 2 import java.util.concurrent.Executors;
 3
 4 /**
 5  * @author Gao
 6  * Date:2016.5
 7  * */
 8 class PriorityTask implements Runnable {
 9     int priority;
10     public PriorityTask(int priority) {
11         this.priority = priority;
12     }
13     @Override
14     public void run() {
15         Thread.currentThread().setPriority(priority);
16         System.out.println(this);
17     }
18     public String toString() {
19         return Thread.currentThread() + ";";
20     }
21 }
22 public class PriorityTest {
23     public static void main(String[] args) {
24         ExecutorService exec = Executors.newCachedThreadPool();
25         for(int i = 0; i < 5; i++)
26             exec.execute(new PriorityTask(Thread.MAX_PRIORITY));
27         exec.execute(new PriorityTask(Thread.MIN_PRIORITY));
28         exec.shutdown();
29
30     }
31 }
32 /*Output:
33 Thread[pool-1-thread-3,10,main];
34 Thread[pool-1-thread-4,10,main];
35 Thread[pool-1-thread-1,10,main];
36 Thread[pool-1-thread-5,10,main];
37 Thread[pool-1-thread-2,10,main];
38 Thread[pool-1-thread-6,1,main];
39
40 */

在该示例中,我们通过给线程设置不同的优先级来定义线程,在线程的信息中会显示其优先级。

2.线程的让步

在第一篇文章的介绍中,我们在例子中应用了Thread.yield( )这一方法,这个方法表现的就是线程的让步。通常我们在run( )方法的其他方法体执行完成之后执行这一方法,意在给线程调度器发送一个信号,告诉线程调度器自己的工作已经基本执行完毕,可以将CPU分配给其他线程进行使用了。但是和上面的线程优先级中的介绍一样,由于CPU处理现有线程集的顺序是不确定的,所以yield( )方法只是给调度器一个建议,并不是真正的在执行yield( )方法后就将CPU分给其他同级别需要CPU的线程。

3.后台线程

(1)后台线程的定义:后台线程是指在程序运行的时候在后台提供一种通用服务的线程,

这种线程一般不属于程序不可缺少的部分。

(2)后台线程的设置:利用线程对象调用setDaemon( )方法,可将其设置为后台线程。

注:必须在线程启动之前设置,才能成功将其设置为后台线程。

三、与线程有关的异常问题

提起异常,想必大家都不会感到陌生。对于多线程编程中来说,如果你不采用一些步骤来捕获这些异常,则一旦异常逃出任务的run( )方法,它就会向外传播到控制台。

目前为了解决线程异常捕获的问题,我们可以通过修改Executor产生线程的方式。实现的基础是Java提供的接口:Thread.UncaughtExceptionHandler。该接口允许程序员在编写的每个Thread对象上都附着一个异常处理器。

ps:有关于异常的例子会在下一篇博文中介绍并解释。

时间: 2024-10-24 12:44:56

Java多线程学习(二)的相关文章

[转]Java多线程学习(总结很详细!!!)

Java多线程学习(总结很详细!!!) 此文只能说是java多线程的一个入门,其实Java里头线程完全可以写一本书了,但是如果最基本的你都学掌握好,又怎么能更上一个台阶呢? 本文主要讲java中多线程的使用方法.线程同步.线程数据传递.线程状态及相应的线程函数用法.概述等.首先让我们来了解下在操作系统中进程和线程的区别: 进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程.(进程是资源分配的最小单位) 线程:同一类线程共享代码和数据空间,

java多线程学习(3)

1)竞争条件 在实际的多线程应用中,通常会有两个或多个线程需要对共同的对象进行共享访问,如果两个线程访问相同的对象,而且每一个都调用了一个会改变对象状态的方法, 那么,线程就会相互倾轧.根据各个线程访问数据的不同顺序,可能会产生腐蚀现象.这种情况通常称为竞争条件. 2)同步 为了多个线程对共享数据的腐蚀,就需要对数据的存取实现同步:常用的同步方法有3种: 1.Reenlock 用Reenlock保护代码块的基本机构如下: 1 Lock myLock=new ReenLock; 2 3 myLoc

java多线程学习(2)

1)Callable和Future Runnable封装一个异步运行的任务:可以当成一个没有任何参数和返回值的异步方法,Callable和 Runnable类似,但是它有返回值和参数. Callable接口是一个参数化的类型,只有一个方法call. 1 public interface Callable<V> 2 3 { 4 5 V call()throws Exception; 6 7 } 类型参数v是指返回值的类型,例如Callable<Integer>代表最终返回一个Inte

java多线程学习(1)

1)多线程与多进程的区别 多线程和多进程有什么区别呢?本质的区别在于每个进程有它自己的变量的完备集,线程则共享相同的数据. 对程序来说,共享的变量会使得线程之间的通信比进程间的通信更加有效和简单:同时,线程相对于进程来说,更加的“轻量级”, 线程的创建和销毁要比 进程的 开销要小的多. 2)多线程程序的构造 多线程的构造通常有两种方法, 第一种方法是,构建一个Thread的子类,并重写它的run()方法: 1 class MyThread extends Thread 2 { 3 4 publi

java多线程学习--java.util.concurrent

CountDownLatch,api 文档:http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes. 假设我们要打印1-100,最

Java多线程(二)、线程的生命周期和状态控制(转)

Java多线程(二).线程的生命周期和状态控制 分类: javaSE综合知识点 2012-09-10 16:11 15937人阅读 评论(3) 收藏 举报 一.线程的生命周期 线程状态转换图: 1.新建状态 用new关键字和Thread类或其子类建立一个线程对象后,该线程对象就处于新生状态.处于新生状态的线程有自己的内存空间,通过调用start方法进入就绪状态(runnable). 注意:不能对已经启动的线程再次调用start()方法,否则会出现java.lang.IllegalThreadSt

java 多线程学习(一)

1 public class ThreadA extends Thread { 2 private static int threadID = 0; 3 4 public ThreadA() { 5 super("ThreadID:" + (++threadID)); 6 } 7 8 public void run() { 9 try { 10 System.out.println(getName() + " 线程运行开始!"); 11 for (int i = 0

黑马程序员之Java多线程学习

android培训  java培训 期待与您交流! 这一篇文章主要关于java多线程,主要还是以例子来驱动的.因为讲解多线程的书籍和文章已经很多了,所以我也不好意思多说,呵呵.大家可以去参考一些那些书籍.我这个文章主要关于实际的一些问题.同时也算是我以后复习的资料吧,.呵呵大家多多指教. 同时希望多结交一些技术上的朋友.谢谢. -------------------------------------------------------------------------------------

Java多线程学习幸运飞艇采集器修复

package javastudy01; class MyThread extends Thread {//重写Run方法public void run(){//1.获取当前线程的名字System.out.println(this.getName()+"我是一个线程."); } public static void main(String[] args) {Java多线程学习幸运飞艇采集器修复,需要请搜索[大神源码论坛]dsluntan.com 客服企娥3393756370 V信170

java核心学习(二十一) 多线程---创建启动线程的三种方式

本节开始java多线程编程的学习,对于操作系统.进程.线程的基本概念不再赘述,只是了解java对于多线程编程的支持有哪些. 一.继承Thread类来创建线程 java语言中使用Thread类来代表线程,代表线程的类可以通过继承Thread类并重写run()方法来实现多线程开发,调用线程类实例的start方法来启动该线程.下面来试一试 package ThreadTest; public class FirstThread extends Thread{ private int i; public