单纯种以一个任务完成之后再进行下一个任务的模式进行,这样下一个任务的开始必须等待前一个任务的结束,只有一个任务完成后才能进行下一个任务。Java 语言提供了并发机制,容许开发人员在程序中执行多个线程,每一个线程完成一个功能,并与其余线程并发执行。这种机制被称为多线程。操做系统以进程为单位,咱们下Windowsjava
系统能够分配给每一个进程一段有限的执行 CPU 的时间(也称为 CPU 时间片),CPU 在这段时间中执行某个进程,而后下一个时间段又跳到另外一个进程中去执行。因为 CPU 切换的速度很是快,给使用者的感觉就是这些任务彷佛在同时运行,因此使用多线程技术后,能够在同一时间内运行更多不一样种类的任务。编程
单任务的特色就是排队执行,也就是同步,就像在 cmd 中输入一条命令后,必须等待这条命令执行完才能够执行下一条命令同样。多线程
CPU 彻底能够在任务 1 和任务 2 之间来回切换,使任务 2 没必要等到 5 秒再运行,系统的运行效率大大获得提高。这就是要使用多线程技术,线程能够理解成是在进程中独立运行的子任务。并发
实现多线程编程的方式主要有两种:一种是继承 Thread 类,另外一种是实现 Runnable 接口ide
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() 方法测试
若是要建立的线程类已经有一个父类,这时就不能再继承 Thread 类,由于 Java 不支持多继承,因此须要实现 Runnable 接口来应对这样的状况this
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() 方法以后,线程处于就绪状态。code
运行状态:当线程获得系统资源后进入运行状态。
等待状态:当处于运行状态下的线程调用 Thread 类的 wait() 方法时,该线程就会进入等待状态。进入等待状态的线程必
须调用 Thread 类的 notify() 方法才能被唤醒。notifyAll() 方法是将全部处于等待状态下的线程唤醒。
休眠状态:当线程调用 Thread 类中的 sleep() 方法时,则会进入休眠状态。
阻塞状态:若是一个线程在运行状态下发出输入/输出请求,该线程将进入阻塞状态,在其等待输入/输出结束时,线程进入就绪状态。对阻塞的线程来讲,即便系统资源关闭,线程依然不能回到运行状态。
死亡状态:当线程的 run() 方法执行完毕,线程进入死亡状态。
为了处理这种共享资源竞争,可使用同步机制。所谓同步机制,指的是两个线程同时做用在一个对象上,应该保持对象数据的统一性和总体性。Java 提供 synchronized 关键字,为防止资源冲突提供了内置支持。
class className{ public synchronized type methodName(){ //代码 } }
synchronized(obj){ //代码 } public class test{ Object obj=new Object(); public void method(){ synchronized(obj){ //代码 } } }
同步的多线程与单线程有本质的区别,当处理一段很是复杂的业务时,使用了多线程处理,只有被synchronized的代码块才会被进行顺序执行,其余的业务代码都是在不一样的线程里各自执行。
返回代码段正在被哪一个线程调用的线程相关信息
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() 方法的做用是判断当前的线程是否处于活动状态。什么是活动状态呢?活动状态就是线程已经启动且还没有终止。线程处于正在运行或准备开始运行的状态,就认为线程是“存活”的
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() 方法的做用是在指定的毫秒数内让当前“正在执行的线程”休眠(暂停执行)
public class MyThread extends Thread { @Override public void run() { System.out.println("开始"); Thread.sleep(2000); //延时2秒 System.out.println("结束"); } }
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() 方法的做用是用来中止线程,但 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() 方法能够在任意状况下强制中止一个线程
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() 释放锁将会给数据形成不一致性的结果。若是出现这样的状况,程序处理的数据就有可能遭到破坏,最终致使程序执行的流程错误,必定要特别注意。