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<>();
相关推荐
w_zero_one8 分钟前
链表(2)
java·数据结构·链表
白杨尚青15 分钟前
C++入门篇(十一):string(中)——容量与增删改查:一篇吃透所有常用接口(万字详解)
java·开发语言·c++
老歌老听老掉牙16 分钟前
旅行商问题:从数学模型到 Python 实战
开发语言·python
CC数分16 分钟前
数据可视化入门:用Python把一堆数字变成一张图
开发语言·python·信息可视化·数据分析
java_nnnn16 分钟前
JavaEE进阶-JavaScript初识
开发语言·前端·javascript·java-ee·ecmascript
SimonKing25 分钟前
SSE、WebSocket 连接丢 Redis 里?那可踩大坑了!
java·后端·程序员
倔强的石头10630 分钟前
【Linux指南】动静态库系列(九):动态库如何进入进程地址空间:从磁盘 .so 到共享内存映射
java·linux·服务器
YYYing.35 分钟前
【设计模式系列 (五) 】原型模式
开发语言·后端·设计模式·原型模式·c/c++
TeamDev36 分钟前
JxBrowser 9.5.2 版本发布啦!
java·前端·windows·chromium·混合应用·jxbrowser·浏览器控件
重生之小比特37 分钟前
【C++进阶】哈希表实现
开发语言·c++·哈希