1、线程状态
public enum State {
/**
* 创建状态
* 尚未启动的新线程处于此状态
*/
NEW,
/**
* 可运行状态
* 处于可运行状态的线程正在Java虚拟机中执行,但它可能正在等待来自操作系统的其他资源,例如处理器
*/
RUNNABLE,
/**
* 阻塞状态
* 等待监视器锁定而被阻塞的线程处于此状态
* 处于阻塞状态的线程正在等待监视器锁进入同步块/方法,或在调用后重新进入同步块/方法
*/
BLOCKED,
/**
* 无限等待状态
* 正在无限期等待另一个线程执行特定操作的线程处于这种状态
* Object.wait with no timeout
* Thread.join with no timeout
*/
WAITING,
/**
* 超时等待状态
* 等待另一个线程在指定等待时间内执行操作的线程处于此状态
* Thread.sleep
* Object.wait with timeout
* Thread.join with timeout
*/
TIMED_WAITING,
/**
* 终止状态
* 线程已完成执行,终止已退出的线程处于此状态
*/
TERMINATED;
}
2、线程优先级
//priority参数表示优先级
private int priority;
//最小优先级
public final static int MIN_PRIORITY = 1;
//默认优先级
public final static int NORM_PRIORITY = 5;
//最大优先级
public final static int MAX_PRIORITY = 10;
public final void setPriority(int newPriority) {
ThreadGroup g;
checkAccess();
if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
throw new IllegalArgumentException();
}
if((g = getThreadGroup()) != null) {
if (newPriority > g.getMaxPriority()) {
newPriority = g.getMaxPriority();
}
setPriority0(priority = newPriority);
}
}
public final int getPriority() {
return priority;
}
优先级越高先执行机会越大,但不一定先执行。
3、创建线程
继承 Thread,重写run()方法
static class MyThread extends Thread {
public MyThread(String name) {
super(name);
}
@Override
public void run() {
System.out.println("线程:" + Thread.currentThread().getName() + " 开始执行!!!");
}
}
private static void demo01() {
MyThread t1 = new MyThread("t1");
t1.start();
}
实现 Runable,重写run()方法,需要Thread类来包装
static class MyThread2 implements Runnable {
@Override
public void run() {
System.out.println("线程:" + Thread.currentThread().getName() + " 开始执行!!!");
}
}
private static void demo01() {
Thread t2 = new Thread(new MyThread2(), "t2");
t2.start();
//匿名内部类
Thread t22 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程:" + Thread.currentThread().getName() + " 开始执行!!!");
}
}, "t22");
t22.start();
//Lamda表达式
Thread t23 = new Thread(() -> System.out.println("线程:" + Thread.currentThread().getName() + " 开始执行!!!"), "t23");
t23.start();
}
实现 Callable,重写call()方法,然后包装成java.util.concurrent.FutureTask, 再然后包装成Thread
static class MyThread3 implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("线程:" + Thread.currentThread().getName() + " 开始执行!!!");
return 1;
}
}
private static void demo01() throws ExecutionException, InterruptedException {
MyThread3 callable = new MyThread3();
FutureTask<Integer> futureTask = new FutureTask<>(callable);
Thread t3 = new Thread(futureTask, "t3");
t3.start();
System.out.println("futureTask = " + futureTask.get());
}
Thread: 继承方式, 不建议使用, 因为Java是单继承的,继承了Thread就没办法继承其它类了,不够灵活
Runnable: 实现接口,比Thread类更加灵活,没有单继承的限制
Callable: Thread和Runnable都是重写的run()方法并且没有返回值,Callable是重写的call()方法并且有返回值并可以借助FutureTask类来判断线程是否已经执行完毕或者取消线程执行
4、start() 和 run()
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程:" + Thread.currentThread().getName() + " 开始执行!!!");
}
}, "t1");
t1.run();
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程:" + Thread.currentThread().getName() + " 开始执行!!!");
}
}, "t2");
t2.start();
run():线程运行时执行的代码块,业务逻辑就写在run方法中;直接调用run方法,仍是main线程执行,而不是由新的线程执行。
start():启动一个线程,Java 虚拟机调用该线程的 run 方法。
5、interrupt() 线程中断
interrupt() :中断本线程(将中断状态标记为true)
isInterrupted():测试当前线程是否已中断。此方法不会影响线程的中断状态。
interrupted() :测试当前线程是否已中断。此方法清除线程的中断状态。换句话说,如果这个方法被连续调用两次,第二次调用将返回false(除非当前线程在第一次调用清除其中断状态之后,第二次调用检查之前再次中断)
public void interrupt() {
if (this != Thread.currentThread())
checkAccess();
synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
interrupt0(); // Just to set the interrupt flag
b.interrupt(this);
return;
}
}
interrupt0();
}
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
public boolean isInterrupted() {
return isInterrupted(false);
}
private native boolean isInterrupted(boolean ClearInterrupted);
6、join() 线程加入
父线程等待子线程的终止。
也就是说父线程的代码块中,如果碰到了子线程的join()方法,此时父线程需要等待(阻塞),等待子线程结束了,才能继续执行join()之后的代码块。
public final void join() throws InterruptedException {
join(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;
}
}
}
示例 join
private static void demo02() {
Thread t1 = new Thread(() -> {
System.out.println("线程:" + Thread.currentThread().getName() + " >> ready");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程:" + Thread.currentThread().getName() + " >> over");
}, "t1");
t1.start();
try {
System.out.println("main线程等待t1线程执行");
t1.join();
// 带参数,则main线程等待一段时间,超时就不理子线程了自己继续执行
// t1.join(3000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("main线程执行完毕");
}
7、yield() 线程礼让
交出CPU的执行时间,不会释放锁,让线程进入就绪状态,等待重新获取CPU执行时间
Thread t1 = new Thread(() -> System.out.println("线程:" + Thread.currentThread().getName() + " 开始执行!!!" ), "t1");
t1.start();
while (Thread.activeCount() > 1) Thread.yield();
System.out.println("线程礼让,子线程跑完,主线程才跑");
8、wait() 和 notify()、notifyAll()
1.wait()的作用是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁。“直到其他线程调用此对象的notify() 方法或 notifyAll() 方法”,当前线程被唤醒(进入“就绪状态”)
2.notify()和notifyAll()的作用,则是唤醒当前对象上的等待线程;notify()是唤醒单个线程,而notifyAll()是唤醒所有的线程。
3.wait(long timeout)让当前线程处于“等待(阻塞)状态”,“直到其他线程调用此对象的notify()方法或 notifyAll() 方法,或者超过指定的时间量”,当前线程被唤醒(进入“就绪状态”)。
注意:
wait()、notify()和notifyAll()都需要在synchronized作用范围中使用
因为wait()方法调用时,会释放线程获得的锁(也就是说当前线程必须持有锁),wait()方法返回后,线程又会重新试图获得锁。
示例 wait
//对象锁
private static final ThreadDemo demo = new ThreadDemo();
private static void demo03() {
Thread t1 = new Thread(demo::method03, "t1");
Thread t2 = new Thread(demo::method031, "t2");
t1.start();
t2.start();
}
private void method03() {
String name = Thread.currentThread().getName();
System.out.println("线程:" + name + " is ready");
try {
Thread.sleep(10);
synchronized (demo) {
System.out.println("线程:" + name + "--> 获取锁");
Thread.sleep(3000);
System.out.println("线程:" + name + "--> 执行wait方法,线程挂起,释放锁,等待被唤醒");
demo.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程:" + name + " is over");
}
private void method031() {
String name = Thread.currentThread().getName();
System.out.println("线程:" + name + " is ready");
try {
Thread.sleep(50);
synchronized (demo) {
System.out.println("线程:" + name + "--> 获取锁");
Thread.sleep(3000);
System.out.println("线程:" + name + "--> 执行notifyAll方法,唤醒其他线程并调用wait方法使自己挂起");
demo.notifyAll();
}
//执行同步代码块后自动释放锁
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程:" + name + " is over");
}
示例 wait 2
// 定义生产最大量
private int productCount = 0;
private static void demo04() {
// 创建t1线程,生产资源
Thread t1 = new Thread(demo::demo04_product, "t1");
// 创建t2线程,消费资源
Thread t2 = new Thread(demo::demo04_customer, "t2");
Thread t3 = new Thread(demo::demo04_customer, "t3");
// 启动线程
t1.start();
t2.start();
t3.start();
}
private synchronized void demo04_product() {
try {
while (true) {
System.out.println(Thread.currentThread().getName() + ":::生产:::" + (++productCount));
Thread.sleep(300);
if (productCount >= 20) {
System.out.println("货舱已满...不必再生产");
notifyAll();
wait();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private synchronized void demo04_customer() {
try {
while (true) {
System.out.println(Thread.currentThread().getName() + ":::消费:::" + productCount);
Thread.sleep(300);
if (productCount <= 1) {
productCount = 0;
System.out.println("货舱已无货...无法消费");
notifyAll();
wait();
} else productCount--;
}
} catch (Exception e) {
e.printStackTrace();
}
}
9、sleep() 和 wait()
sleep是Thread的方法;wait是Object的方法
sleep必须指定时间;wait可以指定也可以不用
sleep可以在任意地方使用;wait在能synchronized范围内使用
sleep释放CPU执行权,但不释放同步锁;wait释放CPU执行权,也释放同步锁,使得其他线程可以使用同步控制块或者方法。