java十九:多线程基础

线程创建两种方式

方式 1:继承 Thread 类

继承后重写run(),调用start()启动线程

java 复制代码
// 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 接口

避免单继承限制,更常用

java 复制代码
// 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();
    }
}

如何实现多线程

java 复制代码
// 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 执行权

java 复制代码
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 同步锁

多线程同时操作共享数据,会出现数据错乱,加锁保证同一时间仅一个线程访问

java 复制代码
//无锁不安全示例
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(线程不安全)

单线程用,多线程绝对不能用!

java 复制代码
Map<String, String> map = new HashMap<>();

2)Hashtable(线程安全,但性能差)

  • 方法全部加 synchronized
  • 多线程会串行等待,性能差
  • 现在基本不用
java 复制代码
Map<String, String> map = new Hashtable<>();

3)Collections.synchronizedMap(安全,性能一般)

把不安全的 Map 包装成安全的

java 复制代码
Map<String, String> map = Collections.synchronizedMap(new HashMap<>());

4)ConcurrentHashMap(企业级首选!

  • Java 最推荐的线程安全 Map
  • 分段锁 / CAS 机制,高并发、高性能
  • 多线程开发必须用它
java 复制代码
Map<String, String> map = new ConcurrentHashMap<>();
相关推荐
小灰灰搞电子31 分钟前
Rust+Slint 实现动态消息提示框源码分享
开发语言·后端·rust
魏 无羡41 分钟前
webclient
java·webclient
神仙别闹1 小时前
基于 C++ 实现两个有序链表序列的交集
java·c++·链表
传奇开心果编程2 小时前
【Rust入门知识点学与练】第21课:Trait 进阶 Advanced Traits
开发语言·学习·rust
新时代牛马2 小时前
字符设备驱动完整篇:从 cdev_add、file_operations 到chrdev_open 与排障
开发语言·python
swordbob2 小时前
ReentrantLock 与 AQS 完整学习手册
java·开发语言
m0_587383003 小时前
全民健身解决方案软件开发实战:从架构设计到落地指南
java·spring boot·spring·架构·需求分析
白山编程大哥3 小时前
Java OutputStreamWriter 详解:从字符到字节的桥梁
java·开发语言·python
shmily麻瓜小菜鸡4 小时前
JavaScript / TypeScript 易踩坑知识点 —— 异步编程类
开发语言·javascript·typescript
一技安身4 小时前
【信创】Docker‑Compose V2 两种离线部署(独立模式、插件模式)简易教程
java·docker·eureka