join()方法的使用
Thread类有一个join
方法,其作用是:在A线程中调用了另外一个线程对象B的join方法时,那么A线程必须等待B线程执行完才能继续往下执行。
public class ThreadTest {
public static void main(String[] args) throws InterruptedException {
long start = System.currentTimeMillis();
System.out.println("程序开始运行!!!");
Thread t1 = new Thread(){
@Override
public void run(){
try {
System.out.println("自定义线程开始启动!!");
Thread.sleep(5000);
System.out.println("自定义线程结束!!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
t1.start();
Thread.sleep(2000);
System.out.println("主线程已执行完毕!!!,等待t1");
long joinstart = System.currentTimeMillis();
t1.join();
System.out.println("主线程:t执行已经执行完毕...,等待了"+(System.currentTimeMillis()-joinstart)/1000+"秒");
System.out.println("程序运行总时间..."+(System.currentTimeMillis()-start)/1000+"秒");
}
}
//Waits for this thread to die.
//等待调用join的线程死亡
public final void join() throws InterruptedException {
join(0);
}
因为程序一启动就启动了主线程,但又启动了t1,主线程2s,t1是5s,如果使用t1.join(),告诉主线程等待t1线程结束后再结束,那么2s后,主线程就已经结束了。
public class ThreadTest {
public static void main(String[] args) throws InterruptedException {
long start = System.currentTimeMillis();
System.out.println("程序开始运行!!!");
Thread t1 = new Thread(){
@Override
public void run(){
for(int i = 0;i<30;i++){
System.out.print(i+" ");
}
}
};
t1.start();
System.out.println("Main 结束!!");
}
}
程序开始运行!!!
Main 结束!!
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
线程的优先级
Java中Thread对象有一个优先级
的概念,优先级被划分10个级别,创建线程的时候,如果没有指定优先级,默认是5。主线程的优先级也是5。优先级高的线程会比优先级低的线程获得更多的运行机会。
**
* The minimum priority that a thread can have. 最小的优先级
*/
public final static int MIN_PRIORITY = 1;
/**
* The default priority that is assigned to a thread.//默认的优先级
*/
public final static int NORM_PRIORITY = 5;
/**
* The maximum priority that a thread can have.//最大的优先级
*/
public final static int MAX_PRIORITY = 10;
/** 返回当前线程的优先级
* Returns this thread's priority.
*
*/
public final int getPriority() {
return priority;
}
public class ThreadTest {
public static void main(String[] args) throws InterruptedException {
System.out.println(Thread.currentThread().getName()+": "+Thread.currentThread().getPriority());
}
}
可以得出,主线程的默认优先级为5
当我们设置两个线程不同的优先级的时候,并不是优先级高的一直优先执行,因为线程是抢占式的,优先级高的只是理论上会优先执行,但并不是所有的操作系统都会支持优先级的设置。
线程的状态
//线程的状态
public enum State {
//线程刚刚被创建,也就是已经new过了,但是还没有调用start()方法
NEW,
//这个状态只是表示,线程是可运行的。
RUNNABLE,
//线程处于阻塞状态,正在等待一个monitor lock。通常情况下,是因为本线程与其他线程公用了
//一个锁。其他在线程正在使用这个锁进入某个synchronized同步方法块或者方法,而本线程进入这个同步代
//码块也需要这个锁,最终导致本线程处于阻塞状态。
BLOCKED,
/**
* 等待状态,调用以下方法会让线程进入等待状态
* <ul>
* <li>{@link Object#wait() Object.wait} with no timeout</li>
* <li>{@link #join() Thread.join} with no timeout</li>
* <li>{@link LockSupport#park() LockSupport.park}</li>
* </ul>
*/
WAITING,
/**
* 线程等待指定的时间
* <ul>
* <li>{@link #sleep Thread.sleep}</li>
* <li>{@link Object#wait(long) Object.wait} with timeout</li>
* <li>{@link #join(long) Thread.join} with timeout</li>
* <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
* <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
* </ul>
*/
TIMED_WAITING,
/**
*线程终止。
*/
TERMINATED;
}
这些状态中NEW状态是开始,TERMINATED时销毁,在整个线程对象的运行过程中,这个两个状态只能出现一次。其他任何状态都可以出现多次,彼此之间可以相互转换。
守护线程
java有两类线程,用户线程(user thread)和守护线程(daemon thread)
daemon thread的作用是为其他的线程提供服务,例如GC线程
可以自行设置守护线程
//这个方法必须在线程开始之前调用
public final void setDaemon(boolean on) {
checkAccess();
if (isAlive()) {
throw new IllegalThreadStateException();
}
daemon = on;
}
ThreadGroup
线程组(ThreadGroup
)表示一个线程的集合。此外,线程组也可以包含其他线程组。线程组构成一棵树,在树中,除了初始线程组(system)外,每个线程组都有一个父线程组。 允许线程访问有关自己的线程组的信息,但是不允许它访问有关其线程组的父线程组或其他任何线程组的信息。
每一个线程产生时,都会被归入某个线程组,视线程是在哪个线程组中产生而定。如果没有指定,则归入产生该子线程的线程的线程组中。
当一个应用启动时,默认会创建两个线程组,system
线程组和main
线程组。其中system线程组是main线程组的父线程组。
system线程组是JVM工作过程中,可能需要一些线程,例如垃圾回收线程,信号转发线程。
main线程组,主要用户创建的线程,如果开发者在创建线程的时候,没有指定线程组,那么就会归于main线程组。
ThreadGroup两大功能:对线程管理和安全,在实际开发中直接使用的比较少,一般我们都是直接使用线程池。
多线程共享资源问题
Java同步代码块(synchronized block
)和锁是用来避免多个线程对共享资源产生竞争,导致运行结果与期望不符合的一种机制。