1.线程设置名字
建议对每个线程启动之前进行定义,不建议启动后和为不同线程设置重名
可以使用Thread类的下面的方法
- 构造方法:
public Thread(Runnable target, String name); - 设置名字:
public final voidsetName(String name); - 取得名字:
public final StringgetName(); - 取得当前线程对象:
public static Thread currentThread();
如果在实例化Thread类对象时候没有设置名字,那么会自动进行编号命名,保证不重复
2.线程的休眠
如果线程持有锁,sleep方法结束前并不会释放该锁
休眠方法
public static void sleep(long millis) throws InterruptedException
调用Thread.sleep(1000)后,线程会被暂停,如果被interrupt,则会抛出InterruptedException异常
Thread.sleep(2000);
3.线程的优先级
优先级越高,越有可能先执行,只是大概率先执行,并不是一定
在Thread类提供
* 设置优先级: public final void setPriority(int newPriority);
* 取得优先级: public final int getPriority();
发现设置和取得优先级都是使用了int数据类型,对于此内容有三种取值:
* 最高优先级: public static final int MAX_PRIORITY; //10
* 中等优先级: public static final int NORM_PRIORITY; //5
* 最低优先级: public static final int MIN_PRIORITY; //1
例子
Thread thread1 = new Thread(task1, "task1线程");
Thread thread2 = new Thread(task2, "task2线程");
thread1.setPriority(Thread.MAX_PRIORITY);
thread1.setPriority(Thread.MIN_PRIORITY);
thread1.start();
thread2.start();
主线程的优先级是多少?
public static void main(String[] args) {
System.out.println(Thread.currentThread().getPriority()); //5,中等
}
4.yield休眠当前线程
休眠当前线程, 是线程编程可执行状态,以便其他相同优先级的线程有机会执行, 使当前线程从执行状态(运行状态)变为可执行态(就绪状态)。cpu会从众多的可执行态里选择,也就是说,当前也就是刚刚的那个线程还是有可能会被再次执行到的,并不是说一定会执行其他线程而该线程在下一次中不会执行到了。
注意: 再次执行调度程序决定的, 可以立刻会再次执行。。。
yield会释放资源锁吗?
yield不会释放资源所,当暂停后,等待调度程序再次调用,走完同步区域代码后才释放锁
package com.study;
public class Test01 implements Runnable {
private String name;
public Test01(String name) {
this.name = name;
}
@Override
public synchronized void run() {
System.out.println(name + "-> start");
for (int i = 0; i < 1000; i++) {
if (i % 2 == 0) {
Thread.yield();
}
System.out.println(Thread.currentThread().getName() + " --- i = " + (i));
}
System.out.println(name + "-> stop");
}
public static void main(String[] args) {
Test01 a = new Test01("A");
Thread thread1 = new Thread(a);
Thread thread2 = new Thread(a);
Thread thread3 = new Thread(a);
thread1.start();
thread2.start();
thread3.start();
}
}
5.join线程之间的并行执行变为串行执行
join等待线程结束
# 等待线程执行结束,或者指定的最大等待时间到了,调用方线程再次被唤醒,如果最大等待时间为0,则只能等线程执行结束,才能被唤醒。
public final void join(long millis) throws InterruptedException
public final void join(long millis, int nanos) throws InterruptedException
public final void join() throws InterruptedException
Thread类中的join方法的主要作用就是同步,它可以使得线程之间的并行执行变为串行执行。
join的意思是使得放弃当前线程的执行,并返回对应的线程
package com.study;
public class Test01 {
public static void main(String[] args) throws InterruptedException {
ThreadJoinTest t1 = new ThreadJoinTest("小明");
ThreadJoinTest t2 = new ThreadJoinTest("小冬");
t1.start();
/**
* 程序在main线程中调用t1线程的join方法,则main线程放弃cpu控制权,并返回t1线程继续执行直到线程t1执行完毕
* 所以结果是t1线程执行完后,才到主线程执行,相当于在main线程中同步t1线程,t1执行完了,main线程才有执行的机会
*/
t1.join();
t2.start();
}
}
class ThreadJoinTest extends Thread {
public ThreadJoinTest(String name) {
super(name);
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(this.getName() + "---" + i);
}
}
}
上面程序结果是先打印完小明线程,在打印小冬线程;
上面注释也大概说明了join方法的作用:在A线程中调用了B线程的join()方法时,表示只有当B线程执行完毕时,A线程才能继续执行。
注意,这里调用的join方法是没有传参的,join方法其实也可以传递一个参数给它的,具体看下面的简单例子:
package com.study;
public class Test01 {
public static void main(String[] args) throws InterruptedException {
ThreadJoinTest t1 = new ThreadJoinTest("小明");
ThreadJoinTest t2 = new ThreadJoinTest("小冬");
t1.start();
/**
* join方法可以传递参数,join(10)表示main线程会等待t1线程10毫秒,10毫秒过去后,
* main线程和t1线程之间执行顺序由串行执行变为普通的并行执行
*/
t1.join(10);
t2.start();
}
}
class ThreadJoinTest extends Thread {
public ThreadJoinTest(String name) {
super(name);
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(this.getName() + "---" + i);
}
}
}
上面代码结果是:程序执行前面10毫秒内打印的都是小明线程,10毫秒后,小明和小冬程序交替打印。
所以,join方法中如果传入参数,则表示这样的意思:如果A线程中掉用B线程的join(10),则表示A线程会等待B线程执行10毫秒,10毫秒过后,A、B线程并行执行。需要注意的是,jdk规定,join(0)的意思不是A线程等待B线程0秒,而是A线程等待B线程无限时间,直到B线程执行完毕,即join(0)等价于join()。
join与start调用顺序问题
上面的讨论大概知道了join的作用了,那么,入股 join在start前调用,会出现什么后果呢?先看下面的测试结果
public class JoinTest {
public static void main(String [] args) throws InterruptedException {
ThreadJoinTest t1 = new ThreadJoinTest("小明");
ThreadJoinTest t2 = new ThreadJoinTest("小东");
/**join方法可以在start方法前调用时,并不能起到同步的作用
*/
t1.join();
t1.start();
//Thread.yield();
t2.start();
}
}
class ThreadJoinTest extends Thread{
public ThreadJoinTest(String name){
super(name);
}
@Override
public void run(){
for(int i=0;i<1000;i++){
System.out.println(this.getName() + ":" + i);
}
}
}
上面代码执行结果是:小明和小东线程交替打印。
所以得到以下结论:join方法必须在线程start方法调用之后调用才有意义。这个也很容易理解:如果一个线程都没有start,那它也就无法同步了。
join方法实现原理
public class HighConcurrency {
public static void main(String[] args) {
try {
Thread threadTest = new Thread(){
public void run(){
System.out.println("执行线程中方法");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
threadTest.start();
synchronized(threadTest){
threadTest.wait(); //当线程终止的时候,会调用线程自身的notifyAll()方法
}
System.out.println("执行到了这里");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
输出
执行线程中方法
执行到了这里
首先开始线程threadTest,在主线程执行到threadTest.wait()时,主线程会等待,奇怪的是主线程并没有别的线程使用notify或notifyAll方法唤醒,竟然直接执行了后面的语句”执行了这里”。
查阅发现如果synchronized获得对象锁是线程的实例时,此时比较特殊,当该线程终止的时候,会调用线程自身的notifyAll()方法,会通知所有等待在该线程对象上的线程
就是利用了线程实例做对象锁时,在线程执行完后,会调用线程自身的notifyAll()方法,此时主线程会接着执行,用处可以控制线程的执行顺序,例如我可以让子线程做计算,在子线程计算完后,在主线程中输出计算结果
有了上面的例子,我们大概知道join方法的作用了,那么,join方法实现的原理是什么呢?
其实,join方法是通过调用线程的wait方法来达到同步的目的的。例如,A线程中调用了B线程的join方法,则相当于A线程调用了B线程的wait方法,在调用了B线程的wait方法后,A线程就会进入阻塞状态,具体看下面的源码:
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) { //如果时执行的join(0)
while (isAlive()) { //如果线程是运行状态,就会执行下面的等待
wait(0);
}
} else { //如果是执行的join(time)
while (isAlive()) { //如果线程时运行状态
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay); //等待delay时间后自动返回继续执行
now = System.currentTimeMillis() - base;
}
}
}
从源码中可以看到:join方法的原理就是调用相应线程的wait方法进行等待操作的,例如A线程中调用了B线程的join方法,则相当于在A线程中调用了B线程的wait方法,当B线程执行完(或者到达等待时间),B线程会自动调用自身的notifyAll方法唤醒A线程,从而达到同步的目的。
核心代码
//如果线程是运行状态,就会执行下面的等待, this.isAlive(), 这个this就是调用的那个线程对象
while (isAlive()) {
wait(0);
}
6.isAlive是否处于活动状态
方法isAlive()功能是判断当前线程是否处于活动状态。
活动状态就是线程启动且尚未终止,比如正在运行或准备开始运行。
package com.study;
class IsAliveThread extends Thread {
public IsAliveThread() {
System.out.println("begin");
System.out.println( Thread.currentThread().getName() + "- status -" + Thread.currentThread().isAlive());
System.out.println("end");
}
@Override
public void run() {
System.out.println("run begin");
System.out.println( Thread.currentThread().getName() + "- status -" + Thread.currentThread().isAlive());
System.out.println("run end");
}
}
public class Test01 {
public static void main(String[] args) {
IsAliveThread ist = new IsAliveThread();
Thread th = new Thread(ist);
System.out.println("Main begin th isAlive = " + th.isAlive());
th.start();
System.out.println("Main end th isAlive = " + th.isAlive());
}
}
3个线程按顺序执行
T3先执行,在T3的run中,调用t2.join,让t2执行完成后再执行t3
在T2的run中,调用t1.join,让t1执行完成后再让T2执行
package testThread;
import java.util.Date;
public class TestThread {
//现在有T1、T2、T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行
public static void main(String[] args) {
//线程1
final Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("t1");
}
});
//线程2
final Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try {
//引用1线程,等待t1线程执行完
t1.join();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("t2");
}
});
//线程3
final Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
try {
//引用2线程,等待t2线程执行完
t2.join();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("t3");
}
});
//这3个线程启动没有先后顺序
t3.start();
t2.start();
t1.start();
}
}
7.中断
java.lang.Thread类有一个interrupt方法,该方法直接对线程调用。当被interrupt的线程正在sleep或wait时,会抛出InterruptedException异常。
事实上,interrupt方法只是改变目标线程的中断状态(interrupt status),而那些会抛出InterruptedException异常的方法,如wait、sleep、join等,都是在方法内部不断地检查中断状态的值。
- interrupt方法
Thread实例方法:必须由其它线程获取被调用线程的实例后,进行调用。实际上,只是改变了被调用线程的内部中断状态;
- Thread.interrupted方法
Thread类方法:必须在当前执行线程内调用,该方法返回当前线程的内部中断状态,然后清除中断状态(置为false) ;
- isInterrupted方法
Thread实例方法:用来检查指定线程的中断状态。当线程为中断状态时,会返回true;否则返回false。

