详解Java多线程基础
作者:爱滑雪的码农
这篇文章给大家介绍了Java多线程基础知识,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
线程创建两种方式
方式 1:继承 Thread 类
继承后重写run(),调用start()启动线程
// 1.定义线程类
class MyThread extends Thread{
@Override
public void run() {
// 线程执行任务
for (int i = 0; i < 5; i++) {
System.out.println("线程执行:"+i);
}
}
}
// 测试
public class ThreadDemo {
public static void main(String[] args) {
MyThread t1 = new MyThread();
t1.start(); // 启动线程,自动执行run方法
}
}方式 2:实现 Runnable 接口
避免单继承限制,更常用
// 1.实现接口
class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("任务运行:"+i);
}
}
}
public class RunnableDemo {
public static void main(String[] args) {
MyRunnable task = new MyRunnable();
Thread t2 = new Thread(task);
t2.start();
}
}如何实现多线程
// 1.定义线程类
class MyThread extends Thread{
@Override
public void run() {
// 线程执行任务
for (int i = 0; i < 5; i++) {
// 加上当前线程名字,你能看清谁在跑
System.out.println(getName() + " 执行:"+i);
}
}
}
// 测试
public class ThreadDemo {
public static void main(String[] args) {
// 创建 2 个线程
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
// 给线程起名字
t1.setName("线程A");
t2.setName("线程B");
// 启动 → 这才是多线程!
t1.start();
t2.start();
}
}
// 1. 定义任务(不是线程,是任务)
class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 5; i++) {
// 打印当前线程名字,能看清谁在跑
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
public class RunnableDemo {
public static void main(String[] args) {
// 1. 创建任务
MyRunnable task = new MyRunnable();
// 2. 创建 2 个线程,执行同一个任务!!!
Thread t1 = new Thread(task, "线程1");
Thread t2 = new Thread(task, "线程2");
// 3. 启动两个线程 → 这就是多线程!
t1.start();
t2.start();
}
}线程生命周期
新建new线程对象-调用start(),等待CPU调度-CPU执行run方法-sleep,等待锁,IO阻塞-任务执行完毕/异常终止
sleep 线程休眠
让线程暂停指定毫秒,让出 CPU 执行权
class SleepThread implements Runnable{
@Override
public void run() {
for (int i = 1; i <= 3; i++) {
System.out.println("计数:"+i);
try {
// 休眠1000毫秒=1秒
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class SleepTest {
public static void main(String[] args) {
new Thread(new SleepThread()).start();
}
}线程安全问题 & synchronized 同步锁
多线程同时操作共享数据,会出现数据错乱,加锁保证同一时间仅一个线程访问
//无锁不安全示例
class Ticket implements Runnable{
private int ticket = 10;
@Override
public void run() {
while (ticket > 0){
System.out.println("剩余票数:"+ticket--);
}
}
}
// 多线程抢票,会出现重复票数、负数票
public class UnSafeTest {
public static void main(String[] args) {
Ticket ticket = new Ticket();
new Thread(ticket,"窗口1").start();
new Thread(ticket,"窗口2").start();
}
}
//synchronized 加锁解决安全问题
class SafeTicket implements Runnable{
private int ticket = 10;
// 锁对象
private final Object lock = new Object();
@Override
public void run() {
while (true){
// 同步代码块,同一时间只允许一个线程进入
synchronized (lock){
if(ticket <= 0){
break;
}
System.out.println(Thread.currentThread().getName()+"出票,剩余:"+ticket--);
}
}
}
}
public class SafeLockTest {
public static void main(String[] args) {
SafeTicket ticket = new SafeTicket();
new Thread(ticket,"窗口A").start();
new Thread(ticket,"窗口B").start();
}
}HashMap vs 线程安全集合
- HashMap:线程不安全,多线程下会出错、数据丢失、死循环。
- 线程安全集合:多线程下不会出错,保证数据正确。
HashMap 为什么线程不安全?
原因:
- 没有加锁
- 多线程同时修改、插入数据时,会互相覆盖、冲突
- JDK 1.8 之前会造成死循环
多线程使用 HashMap 会出现什么问题?
- 数据覆盖
- 数据丢失
- 并发修改异常
- 极端情况下链表成环(卡死)
Java 提供哪些线程安全的 Map?
- Hashtable(古老,效率低)
- Collections.synchronizedMap(Map)(包装成安全 map)
- ConcurrentHashMap(推荐!最常用!高性能!)
1)HashMap(线程不安全)
单线程用,多线程绝对不能用!
Map<String, String> map = new HashMap<>();
2)Hashtable(线程安全,但性能差)
- 方法全部加 synchronized
- 多线程会串行等待,性能差
- 现在基本不用
Map<String, String> map = new Hashtable<>();
3)Collections.synchronizedMap(安全,性能一般)
把不安全的 Map 包装成安全的
Map<String, String> map = Collections.synchronizedMap(new HashMap<>());
4)ConcurrentHashMap(企业级首选!)
- Java 最推荐的线程安全 Map
- 分段锁 / CAS 机制,高并发、高性能
- 多线程开发必须用它
Map<String, String> map = new ConcurrentHashMap<>();
到此这篇关于Java多线程基础的文章就介绍到这了,更多相关java多线程基础内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
