自学内容网 自学内容网

Java——多线程

1.多线程概念

一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务

多线程时多任务的一种特别的形式,但多线程使用了更小的资源开销

所谓进程就是操作系统分配的内存空间和一个或者多个线程

一个线程不能独立存在,必须是进程的一部分,一个进程一直运行,直到所有的非守护线程都结束运行后才能结束

多线程能够满足编写高效率的程序来达到充分利用 CPU 的目的

2.线程的生命周期

新建状态:使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态,该对象就保持这个状态直到程序 start( ) 这个线程

就绪状态:当线程对象调用了 start( ) 这个方法之后,该线程就进入就绪状态,就绪状态的线程处于就绪队列中,要等待 JVM 里线程调度器的调度

运行状态:如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态

阻塞状态:如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:

        等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态

        同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)

        其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态,当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态

死亡状态:一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态

3.优先级

每一个 Java 线程都是有优先级的,使用整数来表示, 取值范围是 1 - 10,优先级依次增加,1 为最小, 10 为最大

4.创建线程

Java 中有三种创建线程的方法:

        实现 Runnable 接口

        继承 Thread 类

实现 Runnable 接口

public class demo1{
    public static void main(String[] args) {
        //使用内部类实现 Runnable 中的 run() 方法
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("这是实现 Runnable 接口的线程2");
            }
        });
        
        Runnable runnable = new Runnable();
        Thread thread1 = new Thread(runnable);

        thread1.start();
        thread2.start();
        /*
        *  输出结果为:
        *    这是实现 Runnable 接口的线程1
        *    这是实现 Runnable 接口的线程2
        */
    }
}
class Runnable implements java.lang.Runnable{
    @Override
    public void run() {
        System.out.println("这是实现 Runnable 接口的线程1");
    }
}

从上面代码可以看到,先创建的线程2,后创建的线程1,但是由于线程1的 start( ) 方法在线程2的 start( ) 方法前面,所有结果是先输出的线程1的结果

继承 Thread 类

public class demo2 {
    public static void main(String[] args) {

        Thread thread1 = new Thread(new ThreadDemo());
        thread1.start();
    }
}
class ThreadDemo extends Thread{
    @Override
    public void run() {
        System.out.println("这是继承 Thread 类的线程");
    }
}

 

Thread 类中的相关方法

start( ) :JVM 调用线程的 run( ) 方法

run( ) :这个方法默认是调用 Runnable 中的 run( ) 方法,如果线程是没有使用 Runnable 创建,那么这个方法什么也不做

setName( ) :改变线程的名称

setPriority( ) :更改线程的优先级

setDaemon( ) :将线程标记成守护线程或者用户线程

join( ) :等待线程的终止时间,单位为毫秒

interrupt( ) :中断线程

isAlive( ) :测试线程是否处于活动状态

5.线程同步

创建一个线程并不会提高程序的执行效率,所以需要创建多个线程,但是当多个线程同时读写同一份资源时,就会引发冲突,例如多个线程同时对一个内存进行读写,就会使写入的数据覆盖,这个时候就需要使用线程同步,让每个线程排队进行操作

synchronized关键字

当用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码

修饰方法时,被修饰的方法叫做同步方法,作用的范围是整个方法,作用的对象是调用这个方法的对象

修饰代码块时,被修饰的代码块叫做同步语句块,作用的范围是大括号 { } 里面的代码,作用的对象是调用这个代码块的对象

实现

模拟银行存取钱的操作,多个线程存取

package test;

class BankAccount  {
    private double balance;

    public BankAccount(double initialBalance) {
        this.balance = initialBalance;
    }

    // 存钱方法
    public synchronized void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
            System.out.println("存入: " + amount + ", 当前余额: " + balance);
        }
    }

    // 取钱方法
    public synchronized void withdraw(double amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
            System.out.println("取出: " + amount + ", 当前余额: " + balance);
        } else {
            System.out.println("取款失败: 余额不足");
        }
    }

    public double getBalance() {
        return balance;
    }
}
class BankTransaction implements java.lang.Runnable {
    private BankAccount account;

    public BankTransaction(BankAccount account) {
        this.account = account;
    }

    @Override
    public void run() {
        // 随机存取钱
        for (int i = 0; i < 5; i++) {
            double amount = Math.random() * 100; // 随机金额
            if (Math.random() > 0.5) {
                account.deposit(amount);
            } else {
                account.withdraw(amount);
            }

            // 睡眠一段时间,模拟处理时间
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}

public class Demo3 {
    public static void main(String[] args) {
        BankAccount account = new BankAccount(1000); // 初始余额1000

        Thread user1 = new Thread(new BankTransaction(account));
        Thread user2 = new Thread(new BankTransaction(account));

        user1.start();
        user2.start();

        try {
            user1.join();
            user2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("最终余额: " + account.getBalance());
    }
}

lock锁

使用 lock( ) 上锁,使用unlock( ) 释放锁

实现

模拟银行存取钱的操作,多个线程存取

package test;

import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Lock;

class BankAccountLock{
    private double balance;
    private final Lock lock = new ReentrantLock(); // 创建Reentrant对象

    public BankAccountLock(double initialBalance) {
        this.balance = initialBalance;
    }

    // 存钱方法
    public void deposit(double amount) {
        lock.lock(); // 获取锁
        try {
            if (amount > 0) {
                balance += amount;
                System.out.println("存入: " + amount + ", 当前余额: " + balance);
            }
        } finally {
            lock.unlock(); // 释放锁
        }
    }

    // 取钱方法
    public void withdraw(double amount) {
        lock.lock(); // 获取锁
        try {
            if (amount > 0 && amount <= balance) {
                balance -= amount;
                System.out.println("取出: " + amount + ", 当前余额: " + balance);
            } else {
                System.out.println("取款失败: 余额不足或金额无效");
            }
        } finally {
            lock.unlock(); // 释放锁
        }
    }

    public double getBalance() {
        return balance;
    }
}

class BankTransactionLock implements java.lang.Runnable {
    private BankAccountLock account;

    public BankTransactionLock(BankAccountLock account) {
        this.account = account;
    }

    @Override
    public void run() {
        // 随机存取钱
        for (int i = 0; i < 7; i++) {
            double amount = Math.random() * 100; // 随机金额
            if (Math.random() > 0.5) {
                account.deposit(amount);
            } else {
                account.withdraw(amount);
            }

            // 睡眠一段时间,模拟处理时间
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}

public class Demo4 {
    public static void main(String[] args) {
        BankAccountLock account = new BankAccountLock(1000); // 初始余额1000

        Thread user1 = new Thread(new BankTransactionLock(account));
        Thread user2 = new Thread(new BankTransactionLock(account));

        user1.start();
        user2.start();

        try {
            user1.join();
            user2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("最终余额: " + account.getBalance());
    }
}

使用场景

时间锁等候、可中断锁等候、无块结构锁、多个条件变量或者锁投票 ,在确实需要一些synchronized所没有的特性的时候,比如时间锁等候、可中断锁等候、无块结构锁、多个条件变量或者锁投票


原文地址:https://blog.csdn.net/xiaoxiao_guai/article/details/140530823

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!