join 方法
join():等待线程运行结束
join(long n):等待线程运行结束,最多等待 n毫秒
interrupt 方法
打断 sleep,wait,join 的线程,这几个方法都会让线程进入阻塞状态,打断 sleep 的线程, 会清空打断状态
守护线程
默认情况下,Java 进程需要等待所有线程都运行结束,才会结束。有一种特殊的线程叫做守护线程,只要其它非守护线程运行结束了,即使守护线程的代码没有执行完,也会强制结束。
class ThreadTest01 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Thread t1 = new Thread(() ->
{
System.out.println("thread begin");
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("thread end");
},"deamon");
t1.setDaemon(true);//不是isDeamon()
t1.start();
System.out.println("main thread begin");
}
}
五种状态

【初始状态】仅是在语言层面创建了线程对象,还未与操作系统线程关联
【可运行状态】(就绪状态)指该线程已经被创建(与操作系统线程关联),可以由 CPU 调度执行,可运行状态在start()方法之后产生
【运行状态】指获取了 CPU 时间片运行中的状态当 CPU 时间片用完,会从【运行状态】转换至【可运行状态】,会导致线程的上下文切换
【阻塞状态】如果调用了阻塞 API,如 BIO 读写文件,这时该线程实际不会用到 CPU,会导致线程上下文切换,进入【阻塞状态】等 BIO 操作完毕,会由操作系统唤醒阻塞的线程,转换至【可运行状态】与【可运行状态】的区别是,对【阻塞状态】的线程来说只要它们一直不唤醒,调度器就一直不会考虑调度它们
【终止状态】表示线程已经执行完毕,生命周期已经结束,不会再转换为其它状态
六种状态

NEW 线程刚被创建,但是还没有调用 start() 方法
RUNNABLE 当调用了 start() 方法之后,注意,Java API 层面的 RUNNABLE 状态涵盖了 操作系统 层面的【可运行状态】、【运行状态】和【阻塞状态】(由于 BIO 导致的线程阻塞,在 Java 里无法区分,仍然认为是可运行)
BLOCKED , WAITING , TIMED_WAITING 都是 Java API 层面对【阻塞状态】的细分
TERMINATED 当线程代码运行结束
共享带来的问题

class ThreadTest01 {
static int counter = 0;
public static void main(String[] args) throws ExecutionException, InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 5000; i++) {
counter++;
}
}, "t1");
Thread t2 = new Thread(() -> {
for (int i = 0; i < 5000; i++) {
counter--;
}
}, "t2");
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(counter);
}
}
临界区 Critical Section
一个程序运行多个线程本身是没有问题的,问题出在多个线程访问共享资源
多个线程读共享资源其实也没有问题,在多个线程对共享资源读写操作时发生指令交错,就会出现问题
一段代码块内如果存在对共享资源的多线程读写操作,称这段代码块为临界区
竞态条件 Race Condition
多个线程在临界区内执行,由于代码的执行序列不同而导致结果无法预测,称之为发生了竞态条件
synchronized 解决方案
阻塞式的解决方案:synchronized,来解决上述问题,即俗称的【对象锁】,它采用互斥的方式让同一时刻至多只有一个线程能持有【对象锁】,其它线程再想获取这个【对象锁】时就会阻塞住。这样就能保证拥有锁的线程可以安全的执行临界区内的代码,不用担心线程上下文切换

synchronized(对象) // 线程1, 线程2(blocked)
{
临界区
}
两个临界区都必须加上对象锁
class ThreadTest01 {
static int counter = 0;
static Object lock = new Object();//静态成员变量
public static void main(String[] args) throws ExecutionException, InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 5000; i++) {
synchronized (lock) {
counter++;//临界区
}
}
}, "t1");
Thread t2 = new Thread(() -> {
for (int i = 0; i < 5000; i++) {
synchronized (lock) {
counter--;
}
}
}, "t2");
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(counter);
}
}
方法上的 synchronized

本文介绍了Java中线程的join方法和interrupt方法,包括它们如何影响线程的执行和中断。此外,还讨论了守护线程的概念,即当所有非守护线程结束后,即使守护线程未完成,程序也会结束。线程的五种状态(初始、可运行、运行、阻塞、终止)和六种状态(NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED)也被详细阐述。文章通过实例展示了共享资源可能导致的问题,如竞态条件,并提出使用synchronized关键字作为解决并发问题的方案。
290

被折叠的 条评论
为什么被折叠?



