多线程编程

本文详细介绍了Java中的并发和并行概念,进程与线程的区别,如何创建和管理线程,包括Thread类的方法和线程状态。还涵盖了线程同步(synchronized和Lock)、线程通信、死锁形成条件以及线程池的工作原理和策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.并发和并行
//在某一时间段同时执行称为并发
//在同一时刻同时执行称为并行
2.进程和线程
//进程拥有自己独立的内存空间,换言之计算机分配资源的单位是进程
//线程是在进程里面,可以共享进程内存资源。
//单个执行核心是通过操作系统的时间分片功能来进行进程和线程之间的处理时间来分配
3.创建线程

Thread类常用构造方法

public Thread(); //创建一个线程
public Thread(String name);//创建一个依据名称的线程
public Thread(Runnable target);//根据给定的线程任务创建一个线程
public Thread(Runnable target, String name);//根据给定的线程任务和名称创建一个线程

Thread类常用成员方法

public synchronized void start();//启动线程但不一定会执行
public final String getName();//获取线程名称
public final synchronized void setName(String name);//设置线程的名称
public final void setPriority(int newPriority);//设置线程的优先级
public final int getPriority();//获取线程的优先级
public final void join() throws InterruptedException;//等待线程执行完成
//等待线程执行给定的时间(单位毫秒)
public final synchronized void join(long millis) throws InterruptedException;
//等待线程执行给定的时间(单位毫秒、纳秒)
public final synchronized void join(long millis, int nanos) throws InterruptedException;
public long getId();//获取线程的ID
public State getState();//获取线程的状态
public boolean isInterrupted();//检测线程是否被打断
public void interrupt();//打断线程

Thread类常用静态方法

public static native Thread currentThread();//获取当前运行的线程
public static boolean interrupted();//检测当前运行的线程是否被打断
public static native void yield();//暂停当前运行的线程,然后再与其他线程争抢资源,称为线程礼让
//使当前线程睡眠给定的时间(单位毫秒)
public static native void sleep(long millis) throws InterruptedException;
//使当前线程睡眠给定的时间(单位毫秒、纳秒)
public static void sleep(long millis, int nanos) throws InterruptedException;

线程的状态:

NEW: 新生。
//当我们new了一个线程时处于该状态
RUNNABLE:可运行。
//调用start方法时,
BLOCKED:阻塞。
WAITING:等待。
TIMED_WAITING:计时等待。
TERMINATED:死亡。
4.线程同步-synchronized
//java语言提供了两种基本的同步习惯用法:同步代码块和同步方法

同步方法语法

访问修饰符 synchronized 返回值类型 方法名(参数列表){
    
}

同步代码块语法

synchronized(对象){
    
}
5.线程同步-Lock
 static class SaleTask implements Runnable{

        private int totalTickets = 10; //售卖10张火车票

        private Lock lock = new ReentrantLock();//创建一个可重入锁

        @Override
        public void run() {
            while (true){
                //尝试获得锁
                if(lock.tryLock()){
                    try {
                        if(totalTickets > 0){
                            String name = Thread.currentThread().getName();
                            System.out.println(name + "售卖火车票:" + totalTickets);
                            totalTickets --;
                        }
                    } finally {
                        lock.unlock();//解锁
                    }
                }
                if(totalTickets == 0) break;
                try {
                    Thread.sleep(100L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
//Lock锁的优势是它们能回避获取锁的企图。
//如果该锁不能立即或在超时到期之前不可用,则tryLock方法将撤消
6.线程通信

Object类中的通信方法

public final native void notify();//唤醒一个在监视器上等待的线程
public final native void notifyAll();//唤醒所有在监视器上等待的线程
public final void wait() throws InterruptedException;//等待
public final native void wait(long timeout) throws InterruptedException;//计时等待
public final void wait(long timeout, int nanos) throws InterruptedException;//计时等待

案例

小明每次没有生活费了就给他的爸爸打电话,他的爸爸知道了后就去银行存钱,钱存好了之后就通知小明去取。

分析

a. 存钱和取钱都有一个共用的账户

b. 存钱后需要通知取钱,然后等待下一次存钱

c.取钱后需要通知存钱,然后等待下一次取钱

7.死锁
//死锁描述了一种情况,两个或多个线程永远被阻塞,互相等待。

死锁形成的条件

1.互斥条件:在某一个时间内某资源只能被一个线程占用。
2.不可剥夺条件:线程未使用完毕的资源不能被其他线程强行夺走。
3.请求与保持条件:线程以及保持了至少一个资源的情况下,还要继续申请资源。

案例分析

 public static void main(String[] args) {

        Object o1 = new Object();
        Object o2 = new Object();
        Runnable r1 = ()->{
            synchronized(o1){
                System.out.println("线程1获得了o1锁资源");
                synchronized(o2){
                    System.out.println("线程1获得了o2锁资源");
                }
            }
        };
        Runnable r2 = ()->{
            synchronized(o2){
                System.out.println("线程2获得了o2锁资源");
                synchronized(o1){
                    System.out.println("线程2获得了o1锁资源");
                }
            }
        };

        Thread t1 = new Thread(r1);
        Thread t2 = new Thread(r2);
        t1.start();
        t2.start();
    }

//上述案例中,线程1获得了锁资源o1,线程2获得了锁资源o2,线程1在等待线程2释放资源,同样,线程2也在等待线程1释放资源,互相等待,形成了死锁。
8.线程池
线程池七大参数:
ThreadPoolExecutor(  
    int corePoolSize,//核心线程数
    int maximumPoolSize,//最大线程数
    long keepAliveTime,//工作线程存活时间
    TimeUnit unit,//时间单位
    BlockingQueue<Runnable> workQueue,//任务队列
    ThreadFactory threadfactory,//线程工厂
    RejectedExecutionHandler handler//拒绝处理器   
)
线程池的工作流程
当一个新的任务提交到线程池中时,首先判断有没有空闲的核心线程,如果有那就将任务交给核心线程来完成;如果没有,就将任务放入任务队列中去等待;当任务队列满了之后,判断是否达到最大线程数,如果没有,就将新任务交给线程工厂新创建的线程完成,当线程工厂创建的线程完成任务,在给定的存活时间内没有新任务,则会消亡。当达到最大线程数时,就会采用拒绝策略来拒绝新的任务。
拒绝的四种策略:
1.AbortPolicy 中止策略 :
	其在拒绝任务时会抛出异常。
2.DiscardPolicy 放弃策略:
	当新的任务被提交时直接放弃。
3.DiscardOldestPolicy 放弃旧的策略:
	该策略在新任务提交时会放弃最老的任务。
4.CallerRunsPolicy 调用方法运行策略:
	当新任务提交后,如果线程池没有关闭且没有执行能力,则把这个任务交给提交任务的线程来执行。
    
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值