并发编程可以使我们将程序划分为多个分离的,独立运行的任务。通过多线程机制,这些独立任务都将由执行线程来驱动。在使用线程时,CPU将轮流给每个任务分配占用时间,每个任务都觉得自己在占用CPU,但实际上CPU时间是划分为片段分配给了所有任务。

定义任务

继承Thread类

我们可以继承Thread类,并重写run方法。

public class SimpleThread extends Thread {
@Override
public void run(){
for(int i = 0; i < 5; i++){
System.out.println(getName() + i);
}
} public static void main(String[] args) {
SimpleThread thread = new SimpleThread();
thread.start();
System.out.println(Thread.currentThread().getName());
}
}

实现Runnable接口

当然,我们还可以实现Runnable接口,并实现run接口,然后提交给Thread实例。

public class Task implements Runnable{
public void run(){
for(int i = 0; i < 5; i++){
System.out.println(Thread.currentThread().getName() + i);
}
}
public static void main(String[] args) {
Thread thread = new Thread(new Task());
thread.start();
System.out.println(Thread.currentThread().getName());
}
}

Callable与Future

我们知道run方法是没有返回值的,也就意味着任务完成后无法获取结果,所以我们需要Callable接口来帮助我们返回任务结果,它和Runnable接口很相似,所以我们也需要实现Callable接口的call方法。而Future接口则用来获取异步计算结果的,我们对执行结果获取,取消,或者判断是否完成。但是Callable接口并没有继承Runnable,所以并不能直接提交给Thread实例,所以我们还需要FutureTask类,它同时实现了Runnable接口和Callable接口,我们可以用FutureTask包装Callable对象,再提交给Thread实例。

import java.util.concurrent.*;

public class TaskWithResult implements Callable<Integer> {
public Integer call(){
int total = 0;
for(int i = 0; i < 100; i++){
total += i;
}
return total;
} public static void main(String[] args) throws InterruptedException, ExecutionException{
RunnableFuture<Integer> task = new FutureTask<Integer>(new TaskWithResult());
Thread thread = new Thread(task);
thread.start();
while (!task.isDone()){
System.out.println(task.get().toString());
}
}
}

 后台线程

       后台线程,也叫守护线程,是指程序在运行的时候在后台提供一种通用服务的线程,并且这种线程并不属于程序中不可或缺的部分。所以,当所有非后台线程结束时,后台线程也会被结束,不管后台线程是否完成。而且,后台线程的子线程也是后台线程。

public class Daemon implements Runnable {
@Override
public void run() {
for(int i = 0; i < 10; i++){
try{
Thread.sleep(1000);
System.out.println(i);
}catch (InterruptedException e){
System.out.println(e.getMessage());
}
}
} public static void main(String[] args) throws InterruptedException{
Thread thread = new Thread(new Daemon());
thread.setDaemon(true);
thread.start();
Thread.sleep(1000 * 5);
System.out.println(Thread.currentThread().getName());
}
}

这里要注意setDaemon方法必须要在start之前调用,才能将其设置为后台线程。

线程的生命周期

新建(new)

当线程被创建时,它只会短暂地处于这种状态。此时它已经分配了必须的系统资源,并执行了初始化。此刻线程已经有资格获得CPU时间了,之后调度器将把这个线程转变为可运行状态或阻塞状态。

就绪(Runnable)

在这种状态下,只要调度器把时间片分配给线程,线程就可以运行。也就是说,在任意时刻,线程可以运行也可以不运行。只要调度器能分配时间片给线程,它就可以运行,这不同于死亡和阻塞状态。

阻塞(Blocked)

线程能够运行,但有某个条件阻止它的运行。当线程处于阻塞状态时,调度器将忽略线程,不会分配给线程任何CPU时间。直到线程重新进入了就绪状态,它才有可能执行操作。

一个任务进入阻塞状态,可能有以下原因:

(1)通过调用sleep()使任务进入休眠状态,在这种情况下,任务在指定时间内不会运行。

(2)通过调用wait()使线程挂起。直到线程得到了notify()或notifyAll()消息,线程才会进入就绪状态。

(3)任务在等待某个输入/输出完成。

(4)任务试图在某个对象上调用其同步控制方法,但是对象锁不可用,因为另外一个任务已经获取了这个锁。

死亡(Dead)

处于死亡或终止状态的线程将不再是可调度的,并且再也不会得到CPU时间,它的任务已结束,或不再是可运行的。任务死亡的通常方式是从run()方法返回,但是任务的线程还可以被中断。

线程控制

线程优先级

线程的优先级将该线程的重要性传递给调度器。尽管CPU处理现有线程集的顺序是不确定的,但是调度器将倾向于让优先级最高的线程先执行。当然,这并不意味着优先权较低的线程将得不到执行(优先级不会导致死锁)。我们可以用getPriority()来读取现有线程的优先级,通过setPriority()来修改它。尽管JDK有10个优先级,但是它与多数操作系统都不能映射的很好。所以设置优先级时,一般使用MAX_PRIORITY、NORM_PRIORITY、MIN_PRIORITY三种级别。

休眠(Sleep)

在线程执行的过程中调用sleep方法让其休眠(也就是进入阻塞状态)。sleep会抛出InterruptedException。

public class Sleep {
public static void main(String[] args) {
System.out.println("休眠开始");
try{
Thread.sleep(1000 * 2);
}catch (InterruptedException e){
System.out.println(e.getMessage());
}
System.out.println("休眠结束");
}
}

让步(Yield)

如果知道已经完成了run方法的循环的一次迭代过程中所需的工作,就可以给线程调度机制一个暗示:你的工作已经做的差不多了,可以让别的线程使用CPU了,这个

暗示将通过调用yeild作出,当然,这只是一种建议,没有任何机制保证它将会采纳。当线程切换出去后,只有优先级与当前线程相同,或优先级比当前线程更高的处于就绪的线程才会获得执行机会,因此完全有可能线程转入就绪后,调度器又将其调度出来重新执行。

Join
   join可以一个让线程等待另一个线程执行完成,调用线程将被阻塞,直到被join的线程执行完成。

public class Task implements Runnable{
public void run(){
for(int i = 0; i < 5; i++){
System.out.println(Thread.currentThread().getName() + i);
}
try{
Thread.sleep(1000);
}catch (InterruptedException e){
System.out.println(e.getMessage());
}
}
public static void main(String[] args) throws Exception{
Thread thread = new Thread(new Task());
thread.start();
thread.join();
System.out.println(Thread.currentThread().getName());
}
}

Java并发基础(上)——Thread的更多相关文章

  1. Java 并发基础

    Java 并发基础 标签 : Java基础 线程简述 线程是进程的执行部分,用来完成一定的任务; 线程拥有自己的堆栈,程序计数器和自己的局部变量,但不拥有系统资源, 他与其他线程共享父进程的共享资源及 ...

  2. java并发基础(二)

    <java并发编程实战>终于读完4-7章了,感触很深,但是有些东西还没有吃透,先把已经理解的整理一下.java并发基础(一)是对前3章的总结.这里总结一下第4.5章的东西. 一.java监 ...

  3. java并发基础及原理

    java并发基础知识导图   一 java线程用法 1.1 线程使用方式 1.1.1 继承Thread类 继承Thread类的方式,无返回值,且由于java不支持多继承,继承Thread类后,无法再继 ...

  4. 【搞定 Java 并发面试】面试最常问的 Java 并发基础常见面试题总结!

    本文为 SnailClimb 的原创,目前已经收录自我开源的 JavaGuide 中(61.5 k Star![Java学习+面试指南] 一份涵盖大部分Java程序员所需要掌握的核心知识.欢迎 Sta ...

  5. Java并发编程:Thread类的使用

    Java并发编程:Thread类的使用 在前面2篇文章分别讲到了线程和进程的由来.以及如何在Java中怎么创建线程和进程.今天我们来学习一下Thread类,在学习Thread类之前,先介绍与线程相关知 ...

  6. 【转】Java并发编程:Thread类的使用

    一.线程的状态 在正式学习Thread类中的具体方法之前,我们先来了解一下线程有哪些状态,这个将会有助于对Thread类中的方法的理解. 线程从创建到最终的消亡,要经历若干个状态.一般来说,线程包括以 ...

  7. java并发基础(五)--- 线程池的使用

    第8章介绍的是线程池的使用,直接进入正题. 一.线程饥饿死锁和饱和策略 1.线程饥饿死锁 在线程池中,如果任务依赖其他任务,那么可能产生死锁.举个极端的例子,在单线程的Executor中,如果一个任务 ...

  8. Java并发基础概念

    Java并发基础概念 线程和进程 线程和进程都能实现并发,在java编程领域,线程是实现并发的主要方式 每个进程都有独立的运行环境,内存空间.进程的通信需要通过,pipline或者socket 线程共 ...

  9. 3、Java并发编程:Thread类的使用

    Java并发编程:Thread类的使用 在前面2篇文章分别讲到了线程和进程的由来.以及如何在Java中怎么创建线程和进程.今天我们来学习一下Thread类,在学习Thread类之前,先介绍与线程相关知 ...

  10. Java并发基础框架AbstractQueuedSynchronizer初探(ReentrantLock的实现分析)

    AbstractQueuedSynchronizer是实现Java并发类库的一个基础框架,Java中的各种锁(RenentrantLock, ReentrantReadWriteLock)以及同步工具 ...

随机推荐

  1. 3D效果

    3D transform:rotate3d(x,y,z,a) (0.6,1,0.5,45deg) transform-origin 允许改变转换元素的位置,(中心点) transform-style ...

  2. git删除远程主机没有的tag

    可以先删除所有本地tag,然后再拉取远程上的tag git tag -l | xargs git tag -d git fetch --tags 其他方法以及查询tag的命令请见:Remove loc ...

  3. Linux文件夹打包发送到本地

    tar -cvf script.tar scriptsz script.tar 具体:  sz/rz命令:  一般来说,linux服务器大多是通过ssh来进行远程的登陆和管理的,如何在命令方式下上传和 ...

  4. 设计模式笔记-观察者(Observer)

    观察者设计模式应该是比较简单的一个设计模式. 定义 定义了对象之间的一对多依赖,这样以来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新. 简单理解就是: 当1个对象状态有所改变的时候,依 ...

  5. 【TCP协议详解】

    为什么会有TCP/IP协议 在世界上各地,各种各样的电脑运行着各自不同的操作系统为大家服务,这些电脑在表达同一种信息的时候所使用的方法是千差万别.就好像圣经中上帝打乱了各地人的口音,让他们无法合作一样 ...

  6. SQL Serever学习8——数据表3

    创建索引 索引就像是字典的目录一样,可以快速的指定需要的数据. 有没有索引的区别 一个没有索引的集合,如果我们需要查找某一个对象,需要遍历整个集合,直到找到匹配的对象,整个工作费时费力,这只是找一个对 ...

  7. angularjs 过滤掉textarea输入内容中夹带的特殊字符

    <body ng-app="app"> <div ng-controller="main"> <textarea ng-model ...

  8. photoshop cc 2014 下载安装及汉化资源及切图简要使用教程

    这是百度经验上一个pscc 2014 版本的下载安装汉化教程,亲测有效: http://jingyan.baidu.com/article/647f0115bce3847f2148a80c.html ...

  9. MAVEN的基本配置,以及Hello Word

    MAVEN介绍 Maven是一个项目构建工具,参与项目创建.jar包管理.编译.运行.打包和发布等过程. Maven工具目的是以一种简便方式在多个项目中共享jar包. MAVEN安装和配置 Maven ...

  10. JD上市前内情:李彦宏雷军柳传志拷问刘强东

    这篇文章是京东上市前夕,在某个会议上刘强东与柳传志.李彦宏.雷军等大佬们的闭门交流实录,由于当时京东正值上市敏感期,文章没有被发出来,现在京东上市了,我想,大家可以看看几位商界大佬对刘强东的“犀利拷问 ...