本文已参与「新人创作礼」活动,一起开启掘金创作之路
1.进程与线程
进程:进程是程序的一次动态执行过程,对应了从代码加载,执行到完成的一个完整过程,这个过程也是从进程本身产生的
线程:线程是比进程更小的执行单位,进程可以产生多个线程,线程与进程类似;,但线程的中断和恢复更加节省系统的开销.
2.线程的状态与生命周期
线程一般有四个状态:
- 新建:当线程类或子类对象被创建时,就处于新建状态,并有了相应的内存空间和其它资源
- 运行:当jvm通过start()方法把cpu使用权交给该线程时,此线程脱离主线程开始生命周期.如果线程是thread的子类创建的,则执行该类中重写父类的run方法,而在线程没有结束时,不可以再让该线程调用start方法,否则发生IllegalThreadStateException异常.
- 中断:原因有四:JVM将cpu资源让给其它线程;执行了线程的sleep方法去进行休眠;执行了wait()方法去进入等待状态,等待时需要由其它线程调用notify()方法去通知它重新进入线程队列排队;进入阻塞状态.
- 死亡:处于死亡状态的线程不具有继续运行的能力,原因有二:已经完成全部工作;强制run()方法结束.死亡状态就是线程释放了实体,即释放分配给线程对象的内存.
3.线程的常用方法
1.start()方法:使之从新建状态进入到就绪状态排队,如已调用start方法,无需再调用,否则会出现异常
2.run()方法:定义线程对象被调度之后所执行的操作,在线程没有结束之前,不赞成让线程再调用start方法,否则出现异常
3.sleep(int 秒数):线程调用sleep方法去放弃CPU资源,休眠一段时间,如果休眠被打断,会抛出异常,异常必须在try-catch语句中调用sleep方法
4.isAlive():查看线程是否处在运行状态,返回true和false
ps:一个线程没有进入死亡状态时,无需分配实体,如果再分配,系统只能引用最后的实体,先前的实体就会存在,不会被垃圾收集器收集.
5.currentThread():是Thread类中的类方法,用类名调用,返回当前使用线程
6.interrupt():线程使用sleep可以用interrupt方法结束休眠重新排队
4.线程同步(synchronize)
目的:若许多线程都需要调用同一个方法时,必须等一个线程结束,另一个线程才能使用方法,不然则会产生混乱(如修改工资表时,先修改了才能发,不然给多钱咋办)
机制:当一个线程A使用synchronize方法时,其它线程想使用就必须等待,直到线程A使用完
5.协调同步的线程
目的:若一个线程使用中用到其它变量,但需要变量经过其它线程修改之后才可以使用,那么可以在同步线程中使用wait()方法去中断该线程的执行,直到其它线程把变量修改合适才使用notifyAll()方法去继续执行
6.守护线程
目的:线程默认是非守护线程,也称作用户(user)线程,线程可以调用setDaemon(boolean on)方法设置成守护线程,当用户线程已结束,守护线程里的run方法还没完成也会结束,所以可以使用守护线程做不重要的工作
下面是多线程使用代码,看懂代码就容易理解了
主线程main方法:
public class thead {
@SuppressWarnings("null")
public static void main(String[] args) throws InterruptedException {// 主线程执行main方法
// TODO Auto-generated method stub
// 线程第一种创建方法:用线程子类
SpeakA b = new SpeakA();
SpeakB w = new SpeakB();
b.setPriority(10);// 设置线程优先权重 ,从1-10之间,不设置就为5,
// JVM线程调度器的任务是使高优先级的线程可以始终运行,一旦时间片有空闲,则让同优先级的的线程轮流使用时间片
b.start();//使用了线程联合方法
w.start();
// 线程第二种创建方法:实现Runnable接口方法(目标对象与线程完全解耦)
Thread SpeakCC, SpeakDD; // 用Thread声明线程
SpeakC sc = new SpeakC(); // 创建目标对象
SpeakC sd = new SpeakC();
SpeakCC = new Thread(sc); // 创建线程,目标对象是SpeakC,SpeakC必须实现Runnable接口
SpeakDD = new Thread(sd);
SpeakCC.setName("sc");
SpeakDD.setName("sd");
SpeakCC.start();
SpeakDD.start();
// 线程第二种创建方法:实现Runnable接口方法(目标对象组合线程弱耦合)使用了线程同步方法
SpeakD D = new SpeakD();
D.DD.start();
D.EE.start();
// 线程第二种创建方法:实现Runnable接口方法(目标对象组合线程弱耦合)使用了协调同步线程方法
SpeakE E = new SpeakE();
E.DD.start();
E.EE.start();
}
}
A方法
public class SpeakA extends Thread { //Thread类的子类创建线程
SpeakB wa = new SpeakB();
@Override
public void run(){ //重写父类的run方法去执行线程所要做的工作
for(int i=1;i<=15;i++){
System.out.println("主人AAA"+i);
try {
wa.join();//线程联合,一起使用
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(i==5){
System.out.println(Thread.interrupted());//查看线程是否被启动为true
System.out.println("主人在睡觉了");
try {
Thread.sleep(1); //Thread休眠多少时间后继续进入队列排队
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
}
}
B方法
public class SpeakB extends Thread { //Thread类的子类创建线程
public void run(){
for(int i=1;i<=10;i++){
System.out.println("下人在扫地"+i);
}
}
}
C方法
public class SpeakC implements Runnable { //实现Runnable接口
public void run() {
// TODO Auto-generated method stub
String name = Thread.currentThread().getName();//获取线程名字
System.out.println(name);
if(name=="sc"){
for(int i=1;i<=10;i++){
System.out.println("主母在喝茶"+i);
}
}else if (name=="sd"){
for(int i=1;i<=10;i++){
System.out.println("下人在泡茶"+i);
}
}
}
}
D方法
public class SpeakD implements Runnable {
Thread DD,EE;
SpeakD(){
DD=new Thread(this);//不加this无法指定
EE=new Thread(this);
}
@Override
public void run() {
Thread t = Thread.currentThread();
if(t==DD){
System.out.println("我是DD");
t.setName("DD");
DE();
}else if(t==EE){
System.out.println("我是EE");
t.setName("EE");
DE();
}
// TODO Auto-generated method stub
}
public synchronized void DE(){//线程同步synchronized修饰方法
Thread t = Thread.currentThread();
for(int i=1;i<=10;i++){
System.out.println("我在使用,别人不能用,我是"+t.getName());
}
}
}
E方法
public class SpeakE implements Runnable {
Thread DD,EE;
SpeakE(){
DD=new Thread(this);//不加this无法指定
EE=new Thread(this);
}
@Override
public void run() {
int i = 10;
Thread t = Thread.currentThread();
if(t==DD){
t.setName("DD");
try {
DE(i);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else if(t==EE){
t.setName("EE");
try {
i=i+20;
DE(i);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// TODO Auto-generated method stub
}
public synchronized void DE(int i) throws InterruptedException{//线程同步synchronized修饰方法
Thread t = Thread.currentThread();
while(i<20){
System.out.println("我没资格用,我是"+t.getName());
wait();//wait方法停止线程
i=i+20;
System.out.println("我充20块钱,我有资格了"+t.getName());
}
notifyAll();//叫醒停止的所有进程
System.out.println("我有资格用,我是"+t.getName());
}
}