1、区别线程和进程
(1)进程:可包含多个线程(大于等于1)。指执行中的程序。
(2)线程:程序中单独顺序的控制流。线程是程序中的顺序控制流,只能使用和分配给程序的资源和环境。
(3)单线程:程序中只存在一个线程,主方法就是一个主线程。
(4)多线程:一个程序中执行多个任务,这样可以更好的使用CPU资源。
2、线程的实现
(1)两种实现方法:继承Thread类和实现Runnable接口
(2)Thread类:在java.lang包中定义的。
格式:
class className extends Thread {run(){};}
(3)Runnable接口同Thread类。
实现Runnable接口的多线程例子
代码1:
package cn.xxs;
/**
* 实现Runnable接口的类
* @author Administrator
*
*/
public class DoSomething implements Runnable {
private String name;
public DoSomething(String name) {
this.name = name;
}
public void run() {
for (int i = 0; i < 5; i++) {
for (long k = 0; k < 100000000; k++) ;
System.out.println(name + ": " + i);
}
}
}
package cn.xxs;
/**
* 测试Runnable类实现的多线程程序
* @author Administrator
*
*/
public class TestRunnable {
public static void main(String[] args) {
DoSomething ds1 = new DoSomething("阿三");
DoSomething ds2 = new DoSomething("李四");
Thread t1 = new Thread(ds1);
Thread t2 = new Thread(ds2);
t1.start();
t2.start();
}
}
结果:
代码2:
package cn.xxs;
/**
* 测试扩展Thread类实现的多线程程序
* @author Administrator
*
*/
public class TestThread extends Thread{
public TestThread(String name) {
super(name);
}
public void run() {
for(int i = 0;i<5;i++){
for(long k= 0; k <100000000;k++);
System.out.println(this.getName()+" :"+i);
}
}
public static void main(String[] args) {
Thread t1 = new TestThread("阿三");
Thread t2 = new TestThread("李四");
t1.start();
t2.start();
}
}
结果:
3、线程的状态及转换详解
(1)创建状态(新状态):准备好了一个多线程的对象
线程对象已经创建,还没有在其上调用start()方法。
(2) 就绪状态(可运行状态):调用了start()方法,等待CPU进行调度。
当线程有资格运行,但调度程序还没有把它选定为运行线程时线程所处的状态。当start()方法调用时,线程首先进入可运行状态。在线程运行之后或者从阻塞、等待或睡眠状态回来后,也返回到可运行状态。
(3)运行状态:执行run()方法
线程调度程序从可运行池中选择一个线程作为当前线程时线程所处的状态。这也是线程进入运行状态的唯一一种方式。
(4)阻塞状态(等待/阻塞/睡眠状态):暂时停止执行,可能将资源交给其他线程使用
这是线程有资格运行时它所处的状态。实际上这个三状态组合为一种,其共同点是:线程仍旧是活的,但是当前没有条件运行。换句话说,它是可运行的,但是如果某件事件出现,他可能返回到可运行状态。
(5)终止状态(死亡状态):线程销毁
当线程的run()方法完成时就认为它死去。这个线程对象也许是活的,但是,它已经不是一个单独执行的线程。线程一旦死亡,就不能复生。如果在一个死去的线程上调用start()方法,会抛出java.lang.IllegalThreadStateException异常。
4、线程的常用方法
(1)获得当前线程对象:currentThread()
(2)获得线程名称:getName()
(3)判断线程是否启动:isAlive()
(4)线程的强行运行:join()
Thread的非静态方法join()让一个线程B“加入”到另外一个线程A的尾部。在A执行完毕之前,B不能工作。例如:
Thread t = new MyThread();
t.start();
t.join();
另外,join()方法还有带超时限制的重载版本。例如t.join(5000);则让线程等待5000毫秒,如果超过这个时间,则停止等待,变为可运行状态。
(5)线程的休眠:sleep()
线程睡眠的原因:线程执行太快,或者需要强制进入下一轮,因为Java规范不保证合理的轮换。
睡眠的实现:调用静态方法。
try {
Thread.sleep(123);
} catch (InterruptedException e) {
e.printStackTrace();
}
睡眠的位置:为了让其他线程有机会执行,可以将Thread.sleep()的调用放线程run()之内。这样才能保证该线程执行过程中会睡眠。
关于线程睡眠需要注意:
----线程睡眠是帮助所有线程获得运行机会的最好方法。
----线程睡眠到期自动苏醒,并返回到可运行状态,不是运行状态。sleep()中指定的时间是线程不会运行的最短时间。因此,sleep()方法不能保证该线程睡眠到期后就开始执行。
----sleep()是静态方法,只能控制当前正在运行的线程。
例子:
package cn.xxs;
/**
* 一个计数器,计数到10,在每个数字之间暂停1秒,每隔2个数字输出一个字符串
* @author Administrator
*
*/
public class MyThread extends Thread {
public void run() {
for (int i = 0; i < 10; i++) {
if ((i) % 2 == 0) {
System.out.println("-------" + i);
}
System.out.print(i);
try {
Thread.sleep(1);
System.out.print("线程睡眠1毫秒!\n");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new MyThread().start();
}
}
结果:
可能使线程离开运行状态的几种情况:
-----------调用Thread.sleep():使当前线程睡眠至少多少毫秒(尽管它可能在指定的时间之前被中断)。
-----------调用Thread.yield():不能保障太多事情,尽管通常它会让当前运行线程回到可运行性状态,使得有相同优先级的线程有机会执行。
----------调用join()方法:保证当前线程停止执行,直到该线程所加入的线程完成为止。然而,如果它加入的线程没有存活,则当前线程不需要停止。
----------线程的run()方法完成。
----------在对象上调用wait()方法(不是在线程上调用)。
----------线程不能在对象上获得锁定,它正试图运行该对象的方法代码。
----------线程调度程序可以决定将当前运行状态移动到可运行状态,以便让另一个线程获得运行机会,而不需要任何理由。
5、线程的优先级
线程默认优先级是5,Thread类中有三个常量,定义线程优先级范围:
(1)按界别来说 1-MIN_PRIORITY、 线程可以具有的最低优先级。
5-NORM_PRIORITY(默认)、 分配给线程的默认优先级。
10-MAX_PRIORITY。 线程可以具有的最高优先级。
6、线程同步
(1)同步:加关键字“synchronized”,称为同步代码块。即
synchronized(同步对象){需要同步的代码块;}
同步方法: synchronized void 方法名称(){}
(2)死锁:两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象。
例子:
package cn.xxs;
public class DeadlockRisk {
private static class Resource {
public int value;
}
private Resource resourceA =new Resource();
private Resource resourceB =new Resource();
public int read() {
synchronized (resourceA) {
synchronized (resourceB) {
return resourceB.value + resourceA.value;
}
}
}
public void write(int a,int b) {
synchronized (resourceB) {
synchronized (resourceA) {
resourceA.value = a;
resourceB.value = b;
}
}
}
}
(3)线程运行周期: