Java入门教程十三(多线程)
线程的概念
单纯种以一个任务完成以后再进行下一个任务的模式进行,这样下一个任务的开始必须等待前一个任务的结束,只有一个任务完成后才能进行下一个任务。Java 语言提供了并发机制,允许开发人员在程序中执行多个线程,每个线程完成一个功能,并与其他线程并发执行。这种机制被称为多线程。操作系统以进程为单位,我们下Windows

系统可以分配给每个进程一段有限的执行 CPU 的时间(也称为 CPU 时间片),CPU 在这段时间中执行某个进程,然后下一个时间段又跳到另一个进程中去执行。由于 CPU 切换的速度非常快,给使用者的感受就是这些任务似乎在同时运行,所以使用多线程技术后,可以在同一时间内运行更多不同种类的任务。
单任务的特点就是排队执行,也就是同步,就像在 cmd 中输入一条命令后,必须等待这条命令执行完才可以执行下一条命令一样。

CPU 完全可以在任务 1 和任务 2 之间来回切换,使任务 2 不必等到 5 秒再运行,系统的运行效率大大得到提升。这就是要使用多线程技术,线程可以理解成是在进程中独立运行的子任务。
实现方式
实现多线程编程的方式主要有两种:一种是继承 Thread 类,另一种是实现 Runnable 接口
Thread类
public Thread(String threadName)
public Thread()
public class NewThread extends Thread{
@Override
public void run(){
//线程的执行代码
}
}
//使用
new NewThread().start();
线程实现的业务代码需要放到 run() 方法中。当一个类继承 Thread 类后,就可以在该类中覆盖 run() 方法,将实现线程功能的代码写入 run() 方法中,然后同时调用 Thread 类的 start() 方法执行线程,也就是调用 run() 方法
Runnable接口
如果要创建的线程类已经有一个父类,这时就不能再继承 Thread 类,因为 Java 不支持多继承,所以需要实现 Runnable 接口来应对这样的情况
public Thread(Runnable r);
public Thread(Runnable r,String name);
public class MyRunnable implements Runnable{
@Override
public void run(){
//线程的执行代码
}
}
//使用
Runnable runnable=new MyRunnable();
Thread thread=new Thread(runnable);
thread.start();
线程的生命周期
线程也具有生命周期,主要包括 7 种状态,分别是出生状态、就绪状态、运行状态、等待状态、休眠状态、阻塞状态和死亡状态

出生状态:用户在创建线程时所处的状态,在用户使用该线程实例调用 start() 方法之前,线程都处于出生状态。
就绪状态:也称可执行状态,当用户调用 start() 方法之后,线程处于就绪状态。
运行状态:当线程得到系统资源后进入运行状态。
等待状态:当处于运行状态下的线程调用 Thread 类的 wait() 方法时,该线程就会进入等待状态。进入等待状态的线程必
须调用 Thread 类的 notify() 方法才能被唤醒。notifyAll() 方法是将所有处于等待状态下的线程唤醒。
休眠状态:当线程调用 Thread 类中的 sleep() 方法时,则会进入休眠状态。
阻塞状态:如果一个线程在运行状态下发出输入/输出请求,该线程将进入阻塞状态,在其等待输入/输出结束时,线程进入就绪状态。对阻塞的线程来说,即使系统资源关闭,线程依然不能回到运行状态。
死亡状态:当线程的 run() 方法执行完毕,线程进入死亡状态。
同步机制 synchronized
为了处理这种共享资源竞争,可以使用同步机制。所谓同步机制,指的是两个线程同时作用在一个对象上,应该保持对象数据的统一性和整体性。Java 提供 synchronized 关键字,为防止资源冲突提供了内置支持。
同步方法
class className{
public synchronized type methodName(){
//代码
}
}
同步块
synchronized(obj){
//代码
}
public class test{
Object obj=new Object();
public void method(){
synchronized(obj){
//代码
}
}
}
同步的多线程与单线程有本质的区别,当处理一段非常复杂的业务时,使用了多线程处理,只有被synchronized的代码块才会被进行顺序执行,其他的业务代码都是在不同的线程里各自执行。
curentThread()
返回代码段正在被哪个线程调用的线程相关信息
public static void main(String[] args)
{
//调用currentThread()方法输出当前线程名称
System.out.println(Thread.currentThread().getName());
}
public class MyThread extends Thread{
@Override
public void run(){
System.out.println(Thread.currentThread().getName());
}
}
MyThread myThread=new MyThread();
Thread t = new Thread(myThread);
t.setName("myThread");
t.start();//输出myThread;
isAlive()
isAlive() 方法的作用是判断当前的线程是否处于活动状态。什么是活动状态呢?活动状态就是线程已经启动且尚未终止。线程处于正在运行或准备开始运行的状态,就认为线程是“存活”的
public class MyThread extends Thread
{
@Override
public void run()
{
System.out.println("run="+this.isAlive());
}
}
public static void main(String[] args)
{
MyThread mythread=new MyThread();
System.out.println("begin="+mythread.isAlive()); //输出线程状态
mythread.start(); //启动线程
System.out.println("end="+mythread.isAlive()); //输出线程状态
}
//输出
begin==false
end==true或false//这里要注意,由于另启一个线程,去执行代码,end有可能在线程启动前执行(此情况end为false),也有可能在线程启动后执行(此情况end为ture)
run=true
sleep()
sleep() 方法的作用是在指定的毫秒数内让当前“正在执行的线程”休眠(暂停执行)
public class MyThread extends Thread
{
@Override
public void run()
{
System.out.println("开始");
Thread.sleep(2000); //延时2秒
System.out.println("结束");
}
}
getId()
getId() 取得正在运行线程的唯一标识
Thread thread=Thread.currentThread();
System.out.println(thread.getId());
线程暂停
暂停线程意味着此线程还可以恢复运行。使用 suspend() 方法暂停线程,使用 resume() 方法恢复线程的执行
public class MyThread extends Thread
{
private long i=0;
public long getI()
{
return i;
}
public void setI(long i)
{
this.i=i;
}
@Override
public void run()
{
while(true)
{
i++;
}
}
}
public static void main(String[] args){
MyThread thread=new MyThread();
thread.start();
System.out.println("线程开始");
System.out.println(System.currentTimeMillis()+" i= "+thread.getI());//输出i的值
thread.suspend();//暂停
System.out.println("线程暂停5秒");
Thread.sleep(5000);
thread.resume();//开始
System.out.println(System.currentTimeMillis()+" i= "+thread.getI());//继续暂停后i的值
}
注意:在使用 suspend() 方法与 resume() 方法时,如果使用不当极易造成公共的同步对象被独占,从而使得其他线程无法访问公共同步对象。使用时要格外注意。
线程停止
停止一个线程意味着在线程处理完任务之前停掉正在做的操作,也就是放弃当前的操作。有三种方法可以停止线程
使用退出标识,使线程正常退出,也就是当 run() 方法完成后线程终止。
使用 stop() 方法强行终止线程,但是不推荐使用这个方法,因为 stop() 和 suspend() 及 resume() 一样,都是作废过期的方法,使用它们可能产生不可预料的结果。
使用 interrupt() 方法中断线程。
interrupt()
interrupt() 方法的作用是用来停止线程,但 intermpt() 方法的使用效果并不像循环结构中 break 语句那样,可以马上停止循环。调用 intermpt() 方法仅仅是在当前线程中打了一个停止的标记,并不是真的停止线程
public class MyThread extends Thread
{
@Override
public void run()
{
for (int i=0;i<10000;i++)
{
System.out.println(i+1);
}
}
}
public static void main(String[] args){
MyThread thread=new MyThread(); //创建MyThread13线程类实例
thread.start(); //启动线程
Thread.sleep(100); //延时100毫秒
thread.interrupt(); //停止线程
}
主线程的运行结果如下所示。从中可以看到,虽然在延时 100 毫秒后调用 intermpt() 方法停止了 thread 线程,但是该线程仍然执行完成输出 10000 行信息。
判断线程是不是停止状态
this.interrupted():测试当前线程是否已经中断。
this.islnterrupted():测试线程是否已经中断。
stop()
调用 stop() 方法可以在任意情况下强制停止一个线程
public class MyThread extends Thread{
private int i=0;
@Override
public void run(){
while (true){
i++;
System.out.println("i=" + i);
Thread.sleep(1000);
}
}
}
MyThread thread=new MyThread();
thread.start();
Thread.sleep(8000);
thread.stop();
线程在启动后有一个 8000 毫秒的延时,在这段时间内会循环 9 次,之后 stop() 方法被执行从而线程停止。运行后输出1到9
调用 stop() 方法时会抛出 java.lang.ThreadDeath 异常,但在通常情况下,此异常不需要显式地捕捉。使用 stop() 释放锁将会给数据造成不一致性的结果。如果出现这样的情况,程序处理的数据就有可能遭到破坏,最终导致程序执行的流程错误,一定要特别注意。
Java入门教程十三(多线程)的更多相关文章
- 无废话ExtJs 入门教程十三[上传图片:File]
无废话ExtJs 入门教程十三[上传图片:File] extjs技术交流,欢迎加群(201926085) 1.代码如下: 1 <!DOCTYPE html PUBLIC "-//W3C ...
- Java入门教程总目录
Java入门教程总目录 持续更新中... 1.Java常识汇总 2.Java框架对比 3.Java技术路线 4.Java编码规范 5.Java环境变量配置 6.枚举 7.操作符 12.定时任务
- Java基础教程:多线程基础(1)——基础操作
Java:多线程基础(1) 实现多线程的两种方式 1.继承Thread类 public class myThread extends Thread { /** * 继承Thread类,重写RUN方法. ...
- Java基础教程:多线程基础(4)——Lock的使用
Java基础教程:多线程基础(4)——Lock的使用 快速开始 Java 5中Lock对象的也能实现同步的效果,而且在使用上更加方便. 本节重点的2个知识点是:ReentrantLock类的使用和Re ...
- Java基础教程:多线程基础(2)——线程间的通信
Java基础教程:多线程基础(2)——线程间的通信 使线程间进行通信后,系统之间的交互性会更强大,在大大提高CPU利用率的同时还会使程序员对各线程任务在处理的过程中进行有效的把控与监督. 线程间的通信 ...
- (一)Java 入门教程
Java 入门教程 Java 是由Sun Microsystems公司于1995年5月推出的高级程序设计语言. Java可运行于多个平台,如Windows, Mac OS,及其他多种UNIX版本的系统 ...
- Java基础教程:多线程基础——线程池
Java基础教程:多线程基础——线程池 线程池 在正常负载的情况瞎,通过为每一个请求创建一个新的线程来提供服务,从而实现更高的响应性. new Thread(runnable).start() 在生产 ...
- Java基础教程:多线程杂谈——双重检查锁与Volatile
Java基础教程:多线程杂谈——双重检查锁与Volatile 双重检查锁 有时候可能需要推迟一些高开销的对象初始化操作,并且只有在使用这些对象时才进行初始化.此时程序员可能会采用延迟初始化.但要正确实 ...
- Java基础教程:多线程基础(6)——信号量(Semaphore)
Java基础教程:多线程基础(6)——信号量(Semaphore) 信号量 信号量(Semaphore)由一个值和一个指针组成,指针指向等待该信号量的进程.信号量的值表示相应资源的使用情况.信号量S≥ ...
随机推荐
- 浅析laravel路由执行原理
包头SEO:目前很多文章已经对Laravel的执行原理做了详细介绍,这里只是为了个人做一下简单记录 首先看入口 index.php 关键的执行函数就是 handle方法 ,但是前面的几个预处理函数,包 ...
- Haploid inheritance|Hardy-Weinberg proportions|
I.2 Haploid inheritance 单倍体也有短暂的二倍体时期: Meiosis:减数分裂 依据图示信息,同时基因型A的频率是p,基因型a的频率是(1-p): 建立Hardy-Weinbe ...
- mediawiki问题
部分内容参考 http://blog.csdn.net/gaogao0603/article/details/7689670 1.启用文件上传:在LocalSettings.php修改或者增加如下:$ ...
- 28)PHP,数据库连接类
PHP代码展示: <?php //类名,也习惯上(推荐)使用跟文件名相似的名字 //定义一个类,该类可以连接mysql数据库 //并连接后返回资源(或失败就终止) class mysqlDB{ ...
- day20-双下new方法,单例模式
# 1. __new__:构造方法,它创造对象,程序员口头语:new一个对象.先执行__new__方法再执行___init__方法. class Goods: def __init__(self):# ...
- mysql之结果集去重
mysql操作中,经常会遇到对结果集的去重 本篇文章列出几种应对办法: 1.使用distinct做去重,测试了一下,DISTINCT可以支持多列去重 select DISTINCT user_id_t ...
- WebService客户端生成方法
1.使用JDK的wsimport.exe产生客户端代码 打开cmd命令框,输入如下格式命令: 格式:wsimport -s "src目录" -p "生成类所在包名&quo ...
- 数论入门——斐蜀定理与拓展欧几里得算法
斐蜀定理 内容 斐蜀定理又叫贝祖定理,它的内容是这样的: 若$a,bin N$,那么对于任意x,y,方程$ax+by=gcd(a,b)*k(kin N)$一定有解,且一定有一组解使$ax+by=gcd ...
- 吴裕雄--天生自然HTML学习笔记:HTML 框架
通过使用框架,你可以在同一个浏览器窗口中显示不止一个页面. iframe语法: <iframe src="URL"></iframe> 该URL指向不同的网 ...
- 你相信吗:空气污染改变了我们的DNA
空气与人类的生存是息息相关的,它直接参与人体的气体代谢.物质代谢和体温调节等过程.世界卫生组织和联合国环境组织发表的一份报告说:"空气污染已成为全世界城市居民生活中一个无法逃避的现实. ...