线程:每个运行的程序都是一个进程,在一个进程中还可以有多个执行单元同时运行,这些执行单元,可以看作程序执行的一条条线索,被称之为线程。
多线程看似同时执行,其实不然,她们和进程一样,也是由CPU轮流执行的,只不过CPU运行的速度很快,故而给人同时执行的感觉。
线程的创建:
1:继承Thread类创建多线程
2:实现Runable接口的run方法
两种实现多线程的方式比较:
java是单继承的 ,如果继承了thread就不能在继承其他的类,而接口在java中可以继承多个,因此大部分人采用第二种方法创建多线程。
后台线程:对于java程序来说,只要还有一个前台程序运行,这个进程就不会结束,如果进程中只有一个后台线程运行,这个程序就会结束。前台线程和后台线程是一种相对的概念,新创建的线程都是前台线程,如果某个线程对象在启动之前,调用了,setDaemon(true)语句,这个线程就会变成一个后台线程。
线程的生命周期及状态转换:
1:新建状态:创建一个线程对象后,该线程对对象就处于新建状态,此时它不能运行,和其他java对象一样,仅仅由java虚拟机分配内存,没有表现出任何线程的动态特征。
2:就绪状态:当线程对象调用了start()方法后,该进程就进入了就绪状态(也可称可运行状态)。处于就绪状态的线程位于可运行池中,此时他具备了,运行的条件,能否获得cpu的使用权开始运行,还需要等待系统的调度。
3:运行状态:线程获得cpu并处于运行状态,且只有就绪状态状态获得cpu变成运行状态,其他状态不能直接变为运行状态
4:阻塞状态:当线程试图获取某个对象的同步锁时,发现该索锁被其他线程所占有,此时线程就会变成阻状态,解除阻塞,变为就绪,必须得到该锁。当线程调用一个阻塞式的IO()方法时,该线程就会进入阻塞状态,如果想进去就绪状态就必须等到这个阻塞方法返回。
5:死亡状态:线程的run()方法正常执行完毕或者线程抛出一个为捕获的异常,错误,线程就会进入死亡状态。一旦进入死亡状态就表示结束了。
线程调度:java中的线程调度采用抢占式的调度模型,即优先级最高的最先获得cpu,Thread static int MAX_PRIORITY 常数10,表示线程的优先级最高位10,还有最低优先级1,普通优先级5,且一个线程的优先级不是一直不变的,我们可以通过Thread setPriority(int)进行设置.
class MaxPriority implements Runnable{
@Override
public void run() {
for(int i=0;i<10;i++)
System.out.println(Thread.currentThread().getName()+"正在输出: "+i);
}
}
class MinPriority implements Runnable{
@Override
public void run() {
for(int i=0;i<10;i++)
System.out.println(Thread.currentThread().getName()+"正在输出: "+i);
}
}
public class Example07 {
public static void main(String[] args) {
//创建两个线程
Thread minPriority = new Thread(new MinPriority(),"优先级较低的线程");
Thread maxPriority = new Thread(new MaxPriority(),"优先级较高的线程");
//设置minPriority的优先级为最小
minPriority.setPriority(1);
maxPriority.setPriority(10);
//开启线程
maxPriority.start();
minPriority.start();
}
}
线程休眠:使用Thread类sleep()方法,可以使正在运行的程序休眠,并让出CPU给其他线程使用。等到休眠的时间到时,便恢复到就绪状态。重新得到CPU。下面程序有连个线程,分别都调用了sleep函数,sleep方法使用时会抛出InterruptedException异常,因此使用时,需要捕获异常。
public class Example08 {
public static void main(String[] args) throws Exception {
//创建两个线程
new Thread (new SleepThread()).start();
for(int i=1;i<=10;i++){
if(i==5){
Thread.sleep(2000);
}
System.out.println("主线程正在输出: "+i);
Thread.sleep(500);
}
}
}
class SleepThread implements Runnable{
@Override
public void run() {
for(int i=1;i<=10;i++){
if(i==3){
try{
Thread.sleep(2000);
}catch(InterruptedException e){
e.printStackTrace();
}
}
System.out.println("线程一正在输出: " + i);
try{
Thread.sleep(5000);
}catch(Exception e){
e.printStackTrace();
}
}
}
}
线程让步:sleep方法,使线程处于阻塞状态,而线程让步中的yiled方法,不会使线程处于阻塞状态,它只是使线程处于就绪状态,让系统从新调度一下而已。
public class Example08 {
public static void main(String[] args) {
//创建两个线程
Thread t1 = new YieldThread("线程A");
Thread t2 = new YieldThread("线程B");
//开启两个线程
t1.start();
t2.start();
}
}
class YieldThread extends Thread{
//定义一个有参的构造方法
public YieldThread(String name){
super(name); //调用父类的构造
}
//重载父类中的run的方法
public void run(){
for(int i=1;i<=5;i++){
System.out.println(Thread.currentThread().getName()+"------ "+i);
if(i==3){
System.out.println("线程让步 :");
Thread.yield(); //线程运行到此,做出让步
}
}
}
}