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)!