多线程
多线程
Java 虚拟机的启动是多线程还是多线程?
由Java命令启动JVM,JVM启动相当于启动了一个进程,接着该进程创建一个主线程去执行main方法。同时会启动的一个垃圾回收进程(避免出现内存溢出),所以至少启动两个线程。
创建线程的两种方法
- 继承Thread类,重写run方法
public class ThreadDemo01 extends Thread{
public static void main(String[] args) {
ThreadDemo01 th1 = new ThreadDemo01();
ThreadDemo01 th2 = new ThreadDemo01();
th1.start();
th2.start();
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread()+"----"+i);
}
}
}
- 实现Runnable接口,实现run()方法
public class ThreadNotifyTest {
public static void main(String[] args) {
Thread th = new Thread(new MyThread(),"th1");
th.start();
}
}
class MyThread implements Runnable{
@Override
public void run() {
}
}
Run()方法和start()方法的区别
- run()方法仅仅是封装该线程执行的代码,直接调用时趋同方法;
- start()方法首先会启动该线程,然后再由JVM去调用该线程的run方法;
线程调度
假设我们的计算机只有一个CPU,那么CPU在一个时刻只能执行一个线程,线程只有得到CPU时间片,也就是使用权,才可以执行指令。线程有两种调度模型:
- 分时调度模型:所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间片;
- 抢占式调度模型:优先让优先级高的线程使用CPU,如果线程的优先级相同,那么随机选择一个,优先级高的线程获得CPU时间片的相对多一些;
- Java使用的是抢占式调度模型
线程生命周期
常用方法
public final void setPriority(int newPriority) //设置线程优先级
- 默认优先级是5,优先级范围[1,10],如果超出优先级范围,会抛java.lang.IllegalArgumentException异常;
- 线程优先级高仅仅表示获取CPU时间片的几率高,优先级高的线程不一定比优先级低的线程优先执行。
public static native void sleep(long millis) //线程睡眠
- 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)。
- 线程睡眠的过程中,如果是在synchronized线程同步内,是持有锁(监视器对象)的。
public final void join() //线程加入
- 只有当前线程执行完成后,再执行其他线程,其他线程阻塞
- 可以想象成插队
public class ThreadJoinTest implements Runnable{
@Override
public void run() {
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread()+"正在执行");
}
}
}
class Test{
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new ThreadJoinTest());
thread.start();
for (int i = 0; i < 20; i++) { //主线程
if (i==10){
thread.join(); //当i=10时,线程加入
}
System.out.println("main");
}
}
}
public static native void yield(); //线程礼让
- 暂停当前正在执行的线程,但不会造成线程阻塞
- 线程由运行状态转变为就绪状态
- 让CPU重新调度,礼让不一定成功
public final void wait(long timeout) //线程等待
- 该方法是Object中的方法,不属于Thread类方法
- wait()使当前线程阻塞,前提是 必须先获得锁,一般配合synchronized 关键字使用,一般在synchronized 同步代码块里使用 wait()
- 当线程执行wait()时,会把当前的锁释放,然后让出CPU,进入阻塞状态,等待其他线程唤醒。
public final void notify() //唤醒线程
- 唤醒正在等待对象监视器的单个线程。 如果任何线程正在等待这个对象,其中一个被选择被唤醒。 选择是任意的,并且由实施的判断发生。
public final void notifyAll() //唤醒所有线程
- 唤醒正在等待对象监视器的所有线程
- 唤醒的线程将无法继续,直到当前线程释放该对象上的锁。
- 唤醒的线程只能由阻塞状态转换成就绪状态,重新与其他线程争夺CPU时间片
线程停止
- 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。
public class ThreadDemo01 extends Thread {
boolean stop =false;
@Override
public void run() {
while (!stop) {
System.out.println(getName() + " is running");
try {
sleep(1000);
} catch (InterruptedException e) {
System.out.println("week up from blcok...");
stop = true; // 在异常处理代码中修改共享变量的状态
}
}
System.out.println(getName() + " is exiting...");
}
public static void main(String[] args) {
ThreadDemo01 demo01 = new ThreadDemo01();
demo01.start();
}
}
- 使用stop方法强行终止,但是不推荐这个方法,已经过期作废。
- 使用interrupt方法中断线程。
守护线程
- 线程分为用户线程和守护线程
- 虚拟机必须确保用户线程执行完毕(手动创建的线程都是用户线程)
- 虚拟机不用等待守护线程执行完毕(GC线程,监控内存等)
public class DaemonTest {
public static void main(String[] args) {
Poeple poeple = new Poeple();
God god = new God();
new Thread(poeple).start();
Thread thread = new Thread(god);
thread.setDaemon(true);//设置为守护线程
thread.start();
}
}
//用户线程
class Poeple implements Runnable{
@Override
public void run() {
for (int i = 0; i < 36500; i++) {
System.out.println("来到人间的第"+i+"天");
}
System.out.println("DoodBye,Workd");
}
}
//守护线程
class God implements Runnable{
@Override
public void run() {
while (true){
System.out.println("默默守护着你!");
}
}
}
sleep()和wait() 的差异
相同点:
- sleep与wait都可以使线程等待,使该线程由运行状态变成阻塞状态
不同点:
- sleep()方法,属于Thread类中的;而wait()方法,属于Object类中 的方法
- sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持者,当 指定的时间到了又会自动恢复运行状态。在调用sleep()方法的过程中,线程不会释放对象锁
- 当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用 notify()方法后本线程才进入对象锁定池准备,获取对象锁进入运行状态。
- wait方法只能在同步块或者同步方法中执行
notify()和notifyAll()的区别
- notify可能会导致死锁,而notifyAll则不会 任何时候只有一个线程可以获得锁,也就是说只有一个线程可以运行synchronized 中的代码 使用notifyall,可以唤醒 所有处于wait状态的线程,使其重新进入锁的争夺队列中,而notify只能唤醒一个。
- wait() 应配合while循环使用,不应使用if,务必在wait()调用前后都检查条件,如果不满足,必须调用 notify()唤醒另外的线程来处理,自己继续wait()直至条件满足再往下执行。

浙公网安备 33010602011771号