Java多线程之Java并行程序基础

版权声明:转载请注明出处!! https://blog.csdn.net/IPI715718/article/details/88378949

进程与线程

进程:计算机中具有某一功能的程序在数据集合上动态运行的过程,是系统进行资源分配的基本单位,数据资源是私有的。

线程:线程是轻量级的进程,是程序调度的最小单位,一个进程包含多个线程,进程的资源数据被线程所共享。

守护线程:守护线程是指在程序的运行过程中为非守护线程(用户线程)提供服务或者支持的线程,当用户线程全部结束后,就意味着守护线程失去了守护的对象,应用程序就结束了,虚拟机自然地退出。例如GC线程和JIT线程都属于守护线程。

线程的生命周期(状态图)

线程的创建我的另一篇https://blog.csdn.net/IPI715718/article/details/82429430

这里强调一下run()方法和start()方法的区别

start()方法是线程的启动方法,一个线程在执行了此方法之后会进入就绪状态或者可执行状态,这时候线程还没有真正的执行,因为当该线程拿不到cpu资源或者锁资源时会停止等待,拿到资源后会调用run()方法进入真正的运行状态。

run()方法是线程体方法,只有在start()方法中自动调用才会起到并行的作用,否则只是当前调用线程执行一个普通方法。

看一下源码

public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        group.add(this);//向线程组中添加该线程

        boolean started = false;
        try {
            start0();//调用本地方法执行run方法
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }

    private native void start0();

    /**
     * If this thread was constructed using a separate
     * <code>Runnable</code> run object, then that
     * <code>Runnable</code> object's <code>run</code> method is called;
     * otherwise, this method does nothing and returns.
     * <p>
     * Subclasses of <code>Thread</code> should override this method.
     *
     * @see     #start()
     * @see     #stop()
     * @see     #Thread(ThreadGroup, Runnable, String)
     */
    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }

线程的基本操作

线程的终止:stop()方法

@Deprecated 
public final void stop() {}

当线程执行完此方法后,该线程会立即放下手中的工作,释放掉cpu资源,并且释放锁资源。这种方法太过于暴力,会强行将程序终止,很可能任务只进行到一半,造成数据的不一致性。

举例:long基本数据类型,64位每次只能写入32位,当第一次写入完成后,线程执行了stop方法,线程立即停止,会造成数据的不完整,读数据是得到的是一个错误的数据。

线程的中断:

线程的中断从字面理解为中断停止的意思,但是实际上自己有一套非常完善的线程退出机制,当线程执行interrupt()后并不会立即停止并且退出程序,而是给线程发一个通知告诉目标线程你需要退出了,至于什么时候停止全部交由目标线程决定,这样就避免了stop()方法的那种暴力行为。

public void interrupt()          //中断线程
public boolean isInterrupted()     //判断线程是否中断
public static boolean interrupted()//判断是否被中断,并清除中断状态  

解释一下三种方法:interrupt方法中断线程,并设置中断标志位。isInterrupted根据中断标志位是否存在,返回该线程是否中断。interrupted根据中断标志位返回该线程是否中断,并且清除掉中断标志位。

以下代码会停止吗?答案不会,会永无休止的打印下去,原因是因为只有标志位,目标线程并没有去写什么时候退出线程的逻辑代码。

public class Test extends Thread {
	@Override
	public void run() {
		int i = 0;
		while(true) {
			System.out.println(i++);
		}
	}
	
	public static void main(String[] args) {
		Test thread = new Test();
		thread.start();
		try {
			sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		thread.interrupt();
	}
}

改进:这样程序会中断。

package test2;

public class Test extends Thread {
	@Override
	public void run() {
		int i = 0;
		while(true) {
			//加入判断是否需要中断和中断推出的逻辑代码
			if(isInterrupted()) {
				break;
			}
			System.out.println(i++);
		}
	}
	
	public static void main(String[] args) {
		Test thread = new Test();
		thread.start();
		try {
			sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		thread.interrupt();
	}
}

等待wait和通知notify/notifyAll

wait()方法和notify() /notifyAll()属于Object的方法,不属于Thread类的方法。Object是所有类的基类,也就意味着所有的对象都可以调用。

在一个线程中当一个对象调用了wait()方法后,该线程将会释放掉锁和cpu资源进入该对象的等待队列中,当该对象执行notify方法后会从该对象的等待队列中随机唤醒一个等待线程,机会平等,人人有机会。当该对象调用notifyAll方法后会唤醒该对象的等待队列中的所有线程。唤醒后的线程进入就绪/可执行状态,只有重新获取cpu和锁资源才能继续执行。

等待线程结束join和谦让yield 

join方法

join方法是等待目标线程结束,在A线程中调用了B线程的join方法,A线程会进入等待,直到B线程执行结束后A线程才能继续执行。

看一下jdk源码

public final void join() throws InterruptedException {
        join(0);
    }

这里调用了下面millis=0。 

public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

最终调用的是 public final synchronized void join(long millis){}方法,

会执行

if (millis == 0) {
    while (isAlive()) {
        wait(0);
    }
}

wait(0)就是当前线程调用了wait()方法,使调用线程进入了当前线程对象的等待池中,当前线程执行结束后,当前线程对象会执行notifyAll方法,唤醒调用线程。

yield 方法

yield 方法是一个静态方法,一旦目标线程线程执行该方法,将会让出cpu资源,不会释放锁,让出资源后立马进入可运行状态,会立刻与其他线程再次进行资源的抢夺,也就意味着该目标线程不一定就不执行。

猜你喜欢

转载自blog.csdn.net/IPI715718/article/details/88378949
今日推荐