Thread的常用方法:
1、Thread类:
public class Thread implements Runnable {
// 线程名字
private volatile String name;
// 线程优先级(1~10)
private int priority; //yeild 当前线程礼让,如果有高优先级,高优先级的先跑
// 守护线程
private boolean daemon ;
// 线程id
private long tid;
// 线程组
private ThreadGroup group;
// 预定义3个优先级
public final static int MIN_PRIORITY = 1;
public final static int NORM_PRIORITY = 5;
public final static int MAX_PRIORITY = 10;
// 构造函数
public Thread();
public Thread(String name);
public Thread(Runnable target);
public Thread(Runnable target, String name);
// 线程组
public Thread(ThreadGroup group, Runnable target);
// 返回当前正在执行线程对象的引用
public static native Thread currentThread();
// 启动一个新线程
public synchronized void start();
// 线程的方法体,和启动线程没关系
public void run();
// 让线程睡眠一会,由活跃状态改为挂起状态
public static native void sleep(long millis) throws InterruptedException;
public static void sleep(long millis, int nanos) throws InterruptedException;
// 打断线程 中断线程 用于停止线程
// 调用该方法时并不需要获取Thread实例的锁。无论何时,任何线程都可以调用其它线程的interruptf方法
public void interrupt();
public boolean isInterrupted()
// 线程是否处于活动状态
public final native boolean isAlive();
// 交出CPU的使用权,从运行状态改为挂起状态
public static native void yield();
public final void join() throws InterruptedException
public final synchronized void join(long millis)
public final synchronized void join(long millis, int nanos) throws InterruptedException
// 设置线程优先级
public final void setPriority(int newPriority);
// 设置是否守护线程
public final void setDaemon(boolean on);
// 线程id
public long getId() { return this.tid; }
// 线程状态
public enum State {
// new 创建
NEW,
// runnable 就绪
RUNNABLE,
// blocked 阻塞
BLOCKED,
// waiting 等待
WAITING,
// timed_waiting
TIMED_WAITING,
// terminated 结束
TERMINATED;
}
}
public static void main(String[] args) {
// main方法就是一个主线程
// 获取当前正在运行的线程
Thread thread = Thread.currentThread();
// 线程名字
String name = thread.getName();
// 线程id
long id = thread.getId();
// 线程优先级
int priority = thread.getPriority();
// 是否存活
boolean alive = thread.isAlive();
// 是否守护线程
boolean daemon = thread.isDaemon();
// Thread[name=main, id=1 ,priority=5 ,alive=true ,daemon=false]
System.out.println("Thread[name=" + name + ", id=" + id + " ,priority=" + priority + " ,alive=" + alive + " ,daemon=" + daemon + "]");
}
2、start()和run():
public static void main(String[] args) throws Exception {
new Thread(()-> {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
try { Thread.sleep(200); } catch (InterruptedException e) { }
}
}, "Thread-A").start();
new Thread(()-> {
for (int j = 0; j < 5; j++) {
System.out.println(Thread.currentThread().getName() + " " + j);
try { Thread.sleep(200); } catch (InterruptedException e) { }
}
}, "Thread-B").start();
}
start(): 启动一个线程,线程之间是没有顺序的,是按CPU分配的时间片来回切换的。
public static void main(String[] args) throws Exception {
new Thread(()-> {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
try { Thread.sleep(200); } catch (InterruptedException e) { }
}
}, "Thread-A").run();
new Thread(()-> {
for (int j = 0; j < 5; j++) {
System.out.println(Thread.currentThread().getName() + " " + j);
try { Thread.sleep(200); } catch (InterruptedException e) { }
}
}, "Thread-B").run();
}
run(): 这个方法不能手动调用,用了start()后自动调用。调用线程的run方法,就是普通的方法调用,虽然将代码封装到两个线程体中,可以看到线程中打印的线程名字都是main主线程,run()方法用于封装线程的代码,具体要启动一个线程来运行线程体中的代码(run()方法)还是通过start()方法来实现,调用run()方法就是一种顺序编程不是并发编程。
3、wait()和notify():
wait、notify和notifyAll方法是Object类的final native方法。所以这些方法不能被子类重写,Object类是所有类的超类,因此在程序中可以通过this或者super来调用this.wait(), super.wait()
wait(): 导致线程进入等待阻塞状态,会一直等待直到它被其他线程通过notify()或者notifyAll唤醒。该方法只能在同步方法中调用。如果当前线程不是锁的持有者,该方法抛出一个IllegalMonitorStateException异常。wait(long timeout): 时间到了自动执行,类似于sleep(long millis)
notify(): 该方法只能在同步方法或同步块内部调用, 随机选择一个(注意:只会通知一个)在该对象上调用wait方法的线程,解除其阻塞状态
notifyAll(): 唤醒所有的wait对象
注意:
Object.wait()和Object.notify()和Object.notifyall()必须写在synchronized方法内部或者synchronized块内部 让哪个对象等待wait就去通知notify哪个对象,不要让A对象等待,结果却去通知B对象,要操作同一个对象
Object
public class Object {
public final void wait() throws InterruptedException;
public final native void wait(long timeout) throws InterruptedException;
public final void wait(long timeout, int nanos) throws InterruptedException;
public final native void notify();
public final native void notifyAll();
}
WaitNotifyTest
public class WaitNotifyTest {
public static void main(String[] args) throws Exception {
WaitNotifyTest waitNotifyTest = new WaitNotifyTest();
new Thread(() -> {
try {
waitNotifyTest.printFile();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
try {
waitNotifyTest.printFile();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
try {
System.out.println(new Date() + "\t" + Thread.currentThread().getName() + "\t睡觉1秒中,目的是让上面的线程先执行,即先执行wait()");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
waitNotifyTest.notifyPrint();
}).start();
}
private synchronized void printFile() throws InterruptedException {
System.out.println(new Date() + "\t" + Thread.currentThread().getName() + "\t等待打印文件...");
this.wait();
System.out.println(new Date() + "\t" + Thread.currentThread().getName() + "\t打印结束。。。");
}
private synchronized void notifyPrint() {
this.notify();
System.out.println(new Date() + "\t" + Thread.currentThread().getName() + "\t通知完成...");
}
}
4、sleep()和wait():
Thread.sleep(long millis): 睡眠时不会释放锁
public static void main(String[] args) throws InterruptedException {
Object lock = new Object();
new Thread(() -> {
synchronized (lock) {
for (int i = 0; i < 5; i++) {
System.out.println(new Date() + "\t" + Thread.currentThread().getName() + "\t" + i);
try { Thread.sleep(1000); } catch (InterruptedException e) { }
}
}
}).start();
Thread.sleep(1000);
new Thread(() -> {
synchronized (lock) {
for (int i = 0; i < 5; i++) {
System.out.println(new Date() + "\t" + Thread.currentThread().getName() + "\t" + i);
}
}
}).start();
}
因main方法中Thread.sleep(1000)所以上面的线程Thread-0先被执行,当循环第一次时就会Thread.sleep(1000)睡眠,因为sleep并不会释放锁,所以Thread-1得不到执行的机会,所以直到Thread-0执行完毕释放锁对象lock,Thread-1才能拿到锁,然后执行Thread-1;
5、总结:
1)、sleep方法和wait方法的区别:
1>、 sleep方法是Thread类的,wait方法是 Object类的
2>、sleep方法 需要传入时间毫秒数 参数, wait 可传 也可以 不传参数
wait方法传入参数,那么和sleep方法类似,在等待指定时间后,会自动恢复为 就绪状态
wait方法如果不传参数,会一直处于等待状态=阻塞状态 , 这种只能手动唤醒
3>、sleep方法释放cpu资源但是不释放锁资源,可以在无锁的环境中使用
wait方法 释放cpu + 锁资源 , 必须在有锁的 环境中使用!
2)、start 方法 和 run 方法
start 方法代表线程进入到 就绪状态 = 该线程拥有抢占cpu资源的 资格
run 方法 代表 线程进入到 运行状态
start方法可以手动调用,当线程抢到资源后,会自动执行run方法
run方法不能手动强行执行,执行不会报错,但是不代表线程开始!
3)、join方法 插队方法
调用该方法后,该线程会优先执行,可以传入时间参数=给与该线程的执行时间
4)、yield 方法 礼让方法
调用该方法,该线程会退出执行状态,重新抢占时间片资源 , 一般使用在 给高优先级线程资源的时候 使用!!!
5)、守护线程 isDaemon() 查看该线程是否是守护线程
setDaemon() 设置该线程是否为守护线程,默认 自定义线程为 非守护线程,守护线程 : 该线程会跟随主线程一起运行完毕,哪怕 该线程自己还没有执行完毕
本电子书目录:《Java基础的重点知识点全集》