线程的生命周期:新建、就绪、运行、阻塞、死亡。
一个线程调用了start()方法后,就由新建态到就绪态,在就绪态抢占到CPU的执行权就进入运行态,在运行态时被别的线程抢走cup的执行权,会重新进入就绪态。在运行态调用了sleep或wait方法,则会进入阻塞态。从阻塞态由于sleep时间到或者被唤醒,则会在此进入就绪态。在运行态如果run结束,或者被中断,则会进入死亡态。在死亡态,对象会等待垃圾回收站回收。
线程与进程的区别:
线程是一个执行单元,进程是一段正在执行的代码,一个进程至少包含一个线程,(也可以包含多个线程),CUP在同一时间只能执行一个进程中的一个线程。
单线程:一个应用程序只有一条执行路径。
多线程:一个应用程序有多条执行路径。
多进程的意义:提高CPU的使用率。
多线程的意义:提高应用程序的使用率。
Java中实现线程的方法:
①继承Thread类:
继承Thread类,实现run方法,在run方法中完成需要完成的逻辑代码的编写,调用start方法开启线程。
package com.whl.thread; public class MyThread extends Thread{ @Override public void run() { while(true){ try { Thread.sleep(1000); System.out.println(Thread.currentThread().getName()+" 运行"); } catch (InterruptedException e) { e.printStackTrace(); } } } }
开启线程如下
package com.whl.thread; public class Test { public static void main(String[] args) { MyThread thread1=new MyThread(); thread1.start(); MyThread thread2=new MyThread(); thread2.start(); } }
运行结果:
②实现Runnable接口
实现Runnable接口,实现run方法,创建实现类对象作为参数,传入到new Thread(实现类对象),然后调用start()方法开启线程。
package com.whl.thread; public class MyOtherThread implements Runnable{ @Override public void run() { while (true) { try { Thread.sleep(1000); System.out.println(Thread.currentThread().getName()+" 执行完毕!!"); } catch (InterruptedException e) { e.printStackTrace(); } } } }
启动时:
package com.whl.thread; public class OtherTest { public static void main(String[] args) { MyOtherThread Thread1=new MyOtherThread(); Thread thread1=new Thread(Thread1); thread1.start(); MyOtherThread Thread2=new MyOtherThread(); Thread thread2=new Thread(Thread2); thread2.start(); } }
运行结果:
Sleep和wait的比较:
sleep(int): 此方法调用线程“睡眠”指定的时间(以毫秒为单位),让出CPU资源,时间到后,线程自然回到就绪态,再次获得CPU后会重新运行。此方法是属于Thread类的静态方法。
wait():等待,让出CPU资源,直到其他的线程对象唤醒(notify()或者notifyAll()),唤醒后也是进入到就绪态继续抢占CPU资源。该方法是Object的方法。
相同之处:都会让出CPU资源而进入阻塞态,都会抛出InterruptedException。
不同之处:如果是加了同步锁,则wait会放弃执行资格,同时释放锁;而sleep虽然会放弃执行资格,但是不会释放锁。
多线程安全问题:
当多个线程同时操作同一共享资源数据的时候,如果存在多条执行语句,会出现某个线程还未执行完完整的语句,就被抢走CPU,从而使数据出现异常。
解决办法:
使用synchronized实现同步,在使用同步的时候,主要关注哪些代码操作了 共享数据,只需要将这部分代码同步即可。
方法一:同步代码块:
synchronized(非空对象) {
代码块
}
方法二:同步方法:
将synchronized作为方法的修饰符来使用。
eg: public synchronized void show(){}
注:同步方法的锁对象是当前对象,this。静态方法的锁对象是当前类对象,类名.class.