Java 线程的优先级是一个整数,其取值范围是 1 (Thread.MIN_PRIORITY ) - 10 (Thread.MAX_PRIORITY )。
默认情况下,每一个线程都会分配一个优先级 NORM_PRIORITY(5)。可以定义线程的优先级,但是这并不能保证高优先级的线程会在低优先级的线程前执行。
具有较高优先级的线程对程序更重要,并且应该在低优先级的线程之前分配处理器资源。但是,线程优先级不能保证线程执行的顺序,而且非常依赖于平台(OS dependent)。
线程调度器
线程调度器是一个操作系统服务,它负责为 Runnable 状态的线程分配 CPU 时间。一旦创建一个线程并启动它,它的执行便依赖于线程调度器的实现。时间分片是指将可用的 CPU 时间分配给可用的 Runnable 线程的过程。分配 CPU 时间可以基于线程优先级或者线程等待的时间。线程调度并不受到 Java 虚拟机控制,所以由应用程序来控制它是更好的选择。
竞态条件
当两个线程竞争同一资源时,如果对资源的访问顺序敏感,就称存在竞态条件。
怎样发现和解决竞争?
在临界区中使用适当的同步就可以避免竞态条件。界区实现方法有两种,一种是用 synchronized,一种是用 Lock 显式锁实现。
上下文切换
单核CPU也支持多线程执行代码,CPU 通过给每个线程分配 CPU 时间片来实现这个机制。时间片是 CPU 分配给各个线程的时间,因为时间片非常短,所以 CPU 通过不停地切换线程执行,让我们感觉多个线程时同时执行的,时间片一般是几十毫秒(ms)。
操作系统中,CPU时间分片切换到另一个就绪的线程,则需要保存当前线程的运行的位置,同时需要加载需要恢复线程的环境信息。
线程不安全
线程安全就是说多线程访问同一代码,会产生不确定的结果。下面这段代码就是线程不安全的典型例子。
/**
-
线程不安全
-
@author Strive
*/
public class NoSafeTicket implements Runnable {
private int allTickets = 10;
@Override
public void run() {
while (allTickets > 0) {
try {
// 扩大时长,模拟实际情况
Thread.sleep(100);
buy();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void buy() {
if (this.allTickets <= 0) {
System.out.println(Thread.currentThread().getName() + “没票可买了”);
} else {
System.out.println(Thread.currentThread().getName() + “买了第” + this.allTickets-- + “张票”);
}
}
public static void main(String[] args) throws Exception {
NoSafeTicket t = new NoSafeTicket();
new Thread(t, “张三”).start();
new Thread(t, “李四”).start();
new Thread(t, “王五”).start();
}
}
程序运行结果:
张三买了第10张票
李四买了第10张票
…
张三买了第3张票
王五买了第3张票
李四买了第3张票
上面这段代码每次运行的结果都会发现变化,但重点在于有人
买到了相同的票
,这是不合理的,这种结果的产升我们可以说这段线程是不安全的
。
线程安全
线程安全就是说多线程访问同一代码,不会产生不确定的结果。
在多线程环境中,当各线程不共享数据的时候,即都是私有(private)成员,那么一定是线程安全的。但这种情况并不多见,在多数情况下需要共享数据,这时就需要进行适当的同步控制了。线程安全一般都涉及到 synchronized, 就是一段代码同时只能有一个线程来操作,不然中间过程可能会产生不可预制的结果。
我们修改一下上面
线程不安全
代码,把他变成线程安全
! buy() 增加synchronized
关键字
public synchronized void buy() {
if (this.allTickets <= 0) {
System.out.println(Thread.currentThread().getName() + “没票可买了”);
} else {
System.out.println(Thread.currentThread().getName() + “买了第” + this.allTickets-- + “张票”);
}
}
程序运行结果:
王五买了第10张票
李四买了第9张票
张三买了第8张票
王五买了第7张票
张三买了第6张票
李四买了第5张票
王五买了第4张票
张三买了第3张票
李四买了第2张票
李四买了第1张票
张三没票可买了
王五没票可买了
如何确保线程安全?
-
对非安全的代码进行加锁控制;
-
使用线程安全的类;
-
多线程并发情况下,线程共享的变量改为方法级的局部变量;
不可变
不可变的对象一定是线程安全的,并且永远也不需要额外的同步。
Java类库中大多数基本数值类如 Integer、String 和 BigInteger 都是不可变的。
小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
的朋友,同时减轻大家的负担。**
[外链图片转存中…(img-jujXGNxo-1710827585764)]
[外链图片转存中…(img-C7tunVNS-1710827585764)]
[外链图片转存中…(img-eRWj6Hsy-1710827585765)]
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
[外链图片转存中…(img-gexeAp5j-1710827585766)]