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<>();
相关推荐
MacroZheng30 分钟前
Claude Code官方桌面端正式发布,夯爆了!
java·人工智能·后端
虚无境38 分钟前
如何编写一个SpringBoot项目告警推送的Starter
java·prometheus·webhook
NE_STOP16 小时前
Vide Coding--AI编程工具的选择
java
LDR00616 小时前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术16 小时前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript
码云数智-园园16 小时前
C++20 Modules 模块详解
java·开发语言·spring
程序员黑豆16 小时前
JDK 下载安装与配置详细教程
java·前端·ai编程
小宇宙Zz17 小时前
Maven依赖冲突
java·服务器·maven
swordbob17 小时前
NIO的channel中什么是 fd(File Descriptor,文件描述符)
java·开发语言·nio