这里总结下java多线程的相关概念java
1.扩展java.lang.Thread类
用户的线程类只须要继承Thread类, 覆盖Thread类的run()方法,而后经过该类的实例对象调用start()方法启动线程便可。程序员
// 类A继承了Thread类
A a = new A();
a.start() // 启动线程
注意:不要覆盖Thread类的start()方法、一个线程只能被启动一次,屡次调用会抛出IllegalThreadStateException异常。web
2.实现Runnable接口
Java不容许一个类继承多个类,所以一旦一个类继承了Thread类,就不能再继承其余的类。为了解决这一问题,Java提供了java.lang.Runnable接口,一样,重写接口中的run()方法便可。编程
// 类A实现了接口Runnable
A a = new A();
Thread t = new Thread(a);
t.start(); // 启动线程
3.实现Callable接口
此方法与实现Runnable接口类似,只不过是要实现call()方法,不经常使用。多线程
Callable和Runnable接口的区别:
a. Callable规定的方法是call(),而Runnable规定的方法是run()。
b. Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。
c. call()方法可抛出异常,而run()方法是不能抛出异常的。并发
阻塞状态(Blocked)
指线程由于某些缘由放弃CPU, 暂时中止运行。当线程处于阻塞状态时,Java虚拟机不会给线程分配CPU,直到线程从新进入就绪状态,它才有机会转到运行状态。
阻塞状态可分为三种:
. 位于对象等待池中的阻塞状态(Blocked in objects’ wait pool): 运行状态时,执行某个对象的wait()方法;
. 位于对象锁池中的阻塞状态(Blocked in object’s lock pool): 当线程处于运行状态,试图得到某个对象的同步锁时,如该对象的同步锁已经被其余线程占用,Java虚拟机就会把这个线程放到这个对象的锁池中;
. 其余阻塞状态(Otherwise Blocked): 当前线程执行了sleep()方法,或者调用了其余线程的join()方法,或者发出了I/O请求时,就会进入这个状态。svg
线程运行状态图解
性能
线程的调度不是跨平台的,它不只取决于Java虚拟机,还依赖于操做系统。 在某些操做系统中,只要运行中的线程没有阻塞,就不会放弃CPU; 在某些操做系统中,即便运行中的线程没有遇到阻塞,也会在运行一段时间后放弃CPU,给其余线程运行机会。
这里简单介绍几个线程中的方法:测试
stop()
Thread类的stop()方法能够强制终止一个线程,但从JDK1.2开始废弃了stop()方法。在实际编程中,通常是在受控制的线程中定义一个标志变量,其余线程经过改变标志变量的值,来控制线程的天然终止、暂停及恢复运行。ui
Thread.sleep(5000);
放弃CPU, 转到阻塞状态。当结束睡眠后,首先转到就绪状态,若有其它线程在运行,不必定运行,而是在可运行池中等待得到CPU。
Thread.interrupt();
中断某个线程
Thread.isInterrupted();
测试某个线程是否被中断,与static boolean interrupted()不一样,对它的调用不会改变该线程的“中断”状态。
join()
挂起当前线程(通常是主线程),直至它所调用的线程终止才被运行。线程A中调用线程B.join(),是使A线程阻塞,由于是A线程调用的B.join()这个方法谁调用谁阻塞。
若是一个同步代码块和非同步代码块同时操纵共享资源,仍然会形成对共享资源的竞争。由于当一个线程执行一个对象的同步代码块时,其余线程仍然能够执行对象的非同步代码块。
每一个对象都有惟一的同步锁。
在静态方法前面也可使用synchronized修饰符。此时该同步锁的对象为类对象(类的Class对象)。
当一个线程开始执行同步代码块时,并不意味着必须以不中断的方式运行。进入同步代码块的线程也能够执行Thread.sleep()或者执行Thread.yield()方法,此时它并无释放锁,只是把运行机会(即CPU)让给了其余的线程。
synchnozied声明不会被继承。
锁对象.wait(): 执行该方法的线程释放对象的锁,Java虚拟机把该线程放到该对象的等待池中。该线程等待其它线程将它唤醒;
锁对象.notify(): 执行该方法的线程唤醒在对象的等待池中等待的一个线程。Java虚拟机从对象的等待池中随机选择一个线程,把它转到对象的锁池中。若是对象的等待池中没有任何线程,那么notify()方法什么也不作。
Thread.yield()静态方法,若是此时具备相同优先级的其余线程处于就绪状态,那么yield()方法将把当前运行的线程放到可运行池中并使另外一个线程运行。若是没有相同优先级的可运行线程,则yield()方法什么也不作。
sleep()和yield()方法都是Thread类的静态方法,区别以下:
sleep()不考虑其余线程优先级;
yield()只会给相同优先级或者更高优先级的线程一个运行的机会。
sleep()转到阻塞状态;
yield()转到就绪状态;
sleep()会抛出InterruptedException异常,
yield()不抛任何异常
sleep()比yield方法具备更好的可移植性。对于大多数程序员来讲,yield()方法的惟一用途是在测试期间人为地提升程序的并发性能,以帮助发现一些隐藏的错误,因此yield()并不经常使用。