第一章 多线程基础

第一章 多线程入门之基础


<<java并发编程之美>>第一章总结

一、

进程:代码在数据集合上一次执行过程,方法区,堆,常量池是共享资源,进程是资源分配的基本单位
线程:进程的一个执行路径,程序计数器和栈是私有资源,线程是cpu资源调度的基本单位

启动main函数相当于启动JVM进程,main函数是main线程

1、线程实现

线程实现有三种方式:继承Thread,实现Runnable,实现Callable三种

//单继承,多个线程执行相同的逻辑只需要多个任务代码
calss MyThread extends Thead{
	@override 
	public void run(){
	}
}
//多个线程执行相同的逻辑只需要一个任务代码,可以通过参数进行任务区分
public class Downloader implements Runnable {
    private String url;
    public Downloader(String url) {
        this.url = url;
    }
    public void run() {
        //根据不同的url 实现不同地下载逻辑
    }
}

// 创建多个下载任务
Downloader task1 = new Downloader("http://example.com/file1");
Downloader task2 = new Downloader("http://example.com/file2");
Downloader task3 = new Downloader("http://example.com/file3");

// 创建线程并启动
new Thread(task1).start();
new Thread(task2).start();
new Thread(task3).start();
//callable有返回值,并且可以抛出异常
public class MyCallable implements Callable<Integer> {
    public Integer call() throws Exception {
        // 执行任务,并返回结果
        int sum = 0;
        for (int i = 0; i <= 100; i++) {
            sum += i;
        }
        return sum;
    }
}

public class Main {
    public static void main(String[] args) throws Exception {
        // 创建Callable对象
        Callable<Integer> myCallable = new MyCallable();

        // 创建FutureTask对象
        FutureTask<Integer> futureTask = new FutureTask<>(myCallable);

        // 创建线程并启动
        Thread thread = new Thread(futureTask);
        thread.start();

        // 获取任务结果
        int result = futureTask.get();
        System.out.println("Result: " + result);
    }
}

2、线程的基本方法

sleep不占用cpu资源,不释放锁
yieldt1的run方法里面执行Thread.yield()方法意味着t1此时会让出cpu,让自己变成就绪状态,此时cpu会从就绪队列里面挑出一个优先级最高的线程优先执行。
join在t2的代码执行t1.join()那么t2被阻塞直到t1运行结束,t2使用wait进行阻塞
wait必须先获得锁,不占用cpu资源,释放锁 ,可以使用notify和interrupt唤醒

//虚假唤醒:仓库有货了才能出库,突然仓库入库了一个货品;这时所有的线程(货车)都被唤醒,来执行出库操作;实际上只有一个线程(货车)能执行出库操作,其他线程都是虚假唤醒
while(条件){
o.wait();
}

interrupt

//interrupt()main线程里面可以调用t1.interrupt()将t1的线程中断标志设为true
//如果t1线程因为join(),wait(),或者sleep()方法发生阻塞,那么t1线程会因为主线程调用了t1.interrupt()方法报错
public static void main(String[] args) throws InterruptedException {
 Thread thread = new Thread(new Runnable() {
 @Override
 public void run() {
 //如果当前线程被中断则退出循环
 while (!Thread.currentThread().isInterrupted())
 System.out.println(Thread.currentThread() + " hello");
 }
 });
 //启动子线程
 thread.start();
 //主线程休眠1s,以便中断前让子线程输出
 Thread.sleep(1000);
 //中断子线程
 System.out.println("main thread interrupt thread");
 thread.interrupt();
 
 //等待子线程执行完毕
 thread.join();
 System.out.println("main is over");
}
//isInterrupted()实例方法不会清除中断标志
//类方法,获取的是当前线程的中断标志,即使在main线程里面调用了t1.interrupted()方法获得也是main线程的中断标志会自动清除线程的中断标志

park和unparkpark和unpark以线程为单位进行等待和唤醒,unpark可以先于park执行。park不会自动释放锁,只能被中断或者唤醒。

import java.util.concurrent.locks.LockSupport;

public class ParkUnparkExample {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            System.out.println("Thread 1 started");
            // 线程 1 调用 park 方法等待
            LockSupport.park();
            System.out.println("Thread 1 resumed");
        });

        Thread t2 = new Thread(() -> {
            System.out.println("Thread 2 started");
            // 线程 2 调用 unpark 方法唤醒线程 1
            LockSupport.unpark(t1);
        });

        t1.start();
        t2.start();
    }
}

3、线程基本概念

线程状态

  • NEW:线程被创建完但是没有t.start()
  • RUNNABLE:t.satrt()之后就是RUNNABLE,分为READY和RUNNING两种
  • BLOCKED:阻塞状态不会占用cpu资源,线程等待锁释放和IO阻塞
  • WAITING:当前线程执行到wait()方法或者LoclSuppot().unpark()方法
  • TIMED_WAITING:Thread.sleep(time),Object.wait(time)或者LockSupport.parkNacos(time)方法限时等待
  • TREMINATE:线程结束任务或者线程执行过程中发生了异常

上下文切换当前线程时间片用完之后就会处于就绪状态
死锁互斥条件,环路等待条件,请求并持有条件,不可剥夺条件,我们可以破换的是环路等待条件和请求并持有条件,用 jps 定位进程 id,再用 jstack id 定位死锁,找到死锁的线程去查看源码,解决优化。
活锁线程1和线程2都试图互相让步,导致它们在不断地切换执行,但是最终没有一个线程能够进展,陷入活锁

public class LiveLockExample {
    public static void main(String[] args) {
        final Object lock = new Object();
        boolean flag = true;

        Thread thread1 = new Thread(new Runnable() {
            public void run() {
                while (flag) {
                    synchronized (lock) {
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            // ignore
                        }
                        System.out.println("Thread 1 wants to yield");
                        Thread.yield();
                    }
                }
            }
        });

        Thread thread2 = new Thread(new Runnable() {
            public void run() {
                while (flag) {
                    synchronized (lock) {
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            // ignore
                        }
                        System.out.println("Thread 2 wants to yield");
                        Thread.yield();
                    }
                }
            }
        });

        thread1.start();
        thread2.start();
    }
}

饥饿线程的优先级过低,导致始终得不到CPU的调度执行
守护线程线程分为守护线程和用户线程,用户线程结束,JVM就会退出

t.setDaemon(true)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值