一、进程和线程的区别
进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1–n个线程。
线程:同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小。
线程和进程一样分为五个阶段:创建、就绪、运行、阻塞、终止。
新建状态(New):新建的线程处于新建状态,如:Thread t = new MyThread();
就绪状态(Runnable):当调用线程对象的start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;
运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就 绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;
阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才 有机会再次被CPU调用以进入到运行状态。根据阻塞产生的原因不同,阻塞状态又可以分为三种:
1.等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;
2.同步阻塞 – 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;
3.其他阻塞 – 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
二、实现线程的方式:
JAVA多线程实现方式主要下面几种:继承Thread类、实现Runnable接口、实现Callable接口、使用ExecutorService。
三、线程调度
Java线程优先级高的线程会获得较多的运行机会
Java线程的优先级用整数表示,取值范围是1~10,Thread类有以下三个静态常量:
static int MAX_PRIORITY:线程可以具有的最高优先级,取值为10。
static int MIN_PRIORITY:线程可以具有的最低优先级,取值为1。
static int NORM_PRIORITY:分配给线程的默认优先级,取值为5。
每个线程都有默认的优先级,缺省优先级为 NORM_PRIORITY。
有关优先级的方法有两个:
final void setPriority(int newp) : 修改线程的当前优先级
final int getPriority() : 返回线程的优先级
主线程的默认优先级为Thread.NORM_PRIORITY。
线程的优先级有继承关系,比如A线程中创建了B线程,那么B将和A具有相同的优先级。
JVM提供了10个线程优先级,但与常见的操作系统都不能很好的映射。如果希望程序能移植到各个操作系统中,
应该仅仅使用Thread类有以下三个静态常量作为优先级,这样能保证同样的优先级采用了同样的调度方式。
//main方法也是一个线程 是普通优先级
public class Test {
public static void main(String[] args) throws InterruptedException {
ThreadTest t1=new ThreadTest();
t1.setName("线程1");//设置线程的名称
t1.start();//启动线程 不能直接调用run方法
// t1.sleep(3000);
ThreadTest t2=new ThreadTest();
t2.setName("线程2");
t2.start();
// t2.start();//不能两次调用start方法
// t2.setPriority(10);//设置线程对象的优先级 参数的范围是0-10 默认为5 数值越大表示执行的时间越长的概率越高
// t1.setPriority(1);
// t1.setPriority(Thread.NORM_PRIORITY);//也可以使字段常量 MAX_PRIORITY MIN_PRIORITY NORM_PRIORITY
/*Thread t = Thread.currentThread();//获得当前正在执行的线程对象
for(int i=0;i<600;i++){
System.out.println(t.getName()+" "+i);
}*/
}
}
//线程:继承Thread类 重写run方法
class ThreadTest extends Thread{
@Override
public void run() {
for(int i=0;i<5000;i++){
/*if(i==100){
try {
sleep(2000);//让线程对象休眠 参数是毫秒数
} catch (InterruptedException e) {
e.printStackTrace();
}
}*/
yield();//谦让 暂停当前正在执行的线程对象,并执行其他线程
System.out.println(this.getName()+" "+i);//获得线程的名称
}
}
}
四、线程join方法
join()方法,等待其他线程终止。在当前线程中调用另一个线程的join()方法,则当前线程转入阻塞状态,直到另一个进程运行结束,当前线程再由阻塞转为就绪状态。
//线程对象互相join 也会死锁
public class Test1 {
public static void main(String[] args) {
Thread1 t1=new Thread1();
Thread2 t2=new Thread2();
t1.t2=t2;//给线程对象的属性赋值
t1.setName("线程1");
t2.t1=t1;
t2.setName("线程2");
t1.start();
t2.start();
}
}
class Thread1 extends Thread{
Thread2 t2;
@Override
public void run() {
for(int i=0;i<500;i++){
if(i==400){
try {
t2.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(getName()+" "+i);
}
}
}
class Thread2 extends Thread{
Thread1 t1;
@Override
public void run() {
for(int i=0;i<500;i++){
if(i==100){
try {
t1.join();//让出当前线程 让t1线程对象执行完
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(getName()+" "+i);
}
}
}
参考资料: