Java多线程

多线程

1.多线程的概念

线程(Thread)是一个程序内部的一条执行流程,多线程是指从软硬件实现的多条执行流程的技术(多条线程由CPU负责调度执行)。

2.多线程的创建
2.1.1创建方式一:继承Thread类
//1.定义一个子类MyThread继承Thread类
public class MyThread extends Thread{
    //2.重写run方法
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("Mythread线程输出"+i);
        }
    }
}

public class ThreadTest {
    //Main方法是有一条默认的主线程负责执行
    public static void main(String[] args) {
        //3.创建MyThread类的对象代表一个线程
        Thread t=new MyThread();
        //4.启动线程
        t.start();
        for (int i = 0; i < 5; i++) {
            System.out.println("Main线程输出"+i);
        }
    }
}
2.1.2优缺点:
  • 优点:编码简单
  • 缺点:线程类已继承Thread,无法继承其他类,不利于功能扩展
2.2.1创建方式二:实现Runnable接口
//1.定义一个任务类实现Runnable接口
public class MyThread2 implements Runnable {
//2.重写Runnable的run方法
    @Override
    public void run() {
        //线程执行任务
        for (int i = 0; i < 10; i++) {
            System.out.println("Mythread2线程输出"+i);
        }
    }
}

public class ThreadTest2 {
    public static void main(String[] args) {
        //3.创建任务对象
        Runnable target=new MyThread2();
        //任务对象并没有start方法,线程对象独有
        //target.start报错
        //4.把任务对象交给一个线程对象处理
        //有参构造器 public Thread(Runnable target)
        new Thread(target).start();
        for (int i = 0; i < 10; i++) {
            System.out.println("Main线程输出"+i);
        }
    }
}
2.2.2优缺点:
  • 优点:任务类只是实现接口,可继承其他类实现其他接口,扩展性强
  • 缺点:需要多创建一个Runnable对象
2.2.3匿名内部类写法
public class MyThread2_2 {
    public static void main(String[] args) {
      //1.直接创建Runnable接口的匿名内部类形式(任务对象)
        Runnable target=new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    System.out.println("子线程1输出"+i);
                }
            }
        };
        //2.交给Thread线程对象并启动
        new Thread(target).start();
        for (int i = 0; i < 5; i++) {
            System.out.println("主线程1输出"+i);
        }
    }
}
//简化方法1:
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    System.out.println("子线程2输出"+i);
                }
            }
        }).start();
//简化方法2:
        new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                System.out.println("子线程3输出"+i);
            }
        }).start();
2.3.1创建方式三:实现Callable接口
//1.实现Callable接口
public class MyCallable implements Callable<String> {
    private  int n;
    public MyCallable(int n) {
        this.n = n;
    }
    //2.重写call方法
    @Override
    public String call() throws Exception {
        //描述线程的任务,返回线程执行的结果
        int sum=0;
        for (int i = 0; i < n; i++) {
            sum+=i;
        }
        return "线程求出的结果是"+sum;
    }
}

public class ThreadTest3 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //3.创建Callable对象
        Callable<String> call=new MyCallable(100);
        //4.把Callable对象封装成FutureTask对象(任务对象)
        //未来任务对象的作用
        //1.是一个任务对象,实现了Runnable对象
        //2.线程执行完毕后,用未来任务对象调用get方法获取执行完毕的结果
        FutureTask<String> f1=new FutureTask<>(call);
        //5.任务对象交给线程对象
        new Thread(f1).start();
        //6.获取执行完毕结果
        String rs = f1.get();
        System.out.println(rs);
    }


}

2.3.2优缺点:
  • 优点:任务类只是实现接口,可继承其他类实现其他接口,扩展性强,可以在线程执行后获取执行的结果
  • 缺点:编码复杂
2.3多线程注意事项

1.启动线程必须调用start方法,而不是调用run方法
run方法相当于一个普通对象来运行,会导致run方法里面的代码先执行完,不符合多线程运行
start方法相当于向CPU注册一个单独的执行流程,调度时虽然也是执行run方法
2.不要把主线程任务放在启动子线程之前
会导致永远都是主任务先跑完才会运行子线程,子线程都没启动起来又谈何运行

3.1 Thread常用方法及构造器
public void run() 
public void start()
public String getNmae()
public void setNmae(String name)
public static Thread currentThread()//当前线程名称
public static void sleep(long time)//睡眠ms
public final void join() //先执行完该进程
    
常见构造器
public Thread (String name)
public Thread (Runnable target) 
public Thread(Runnable target,String name)
4.线程安全问题
4.1什么是安全问题

多个线程,同时操作同一个共享资源的时候,可能会出现业务安全问题。

4.2出现线程安全问题的原因

1.存在多个线程在同时执行 2.同时访问同一共享资源 3.存在修改共享资源

4.3线程同步

加锁:每次只允许一个线程加锁,加锁后才能进行访问,访问完毕自动解锁,然后其他线程才能加锁进来

4.3.1方式一:同步代码块
作用:把访问共享资源的核心代码给上锁,以此保证线程安全
同步锁注意事项:对于当前执行的县城来说,同步锁必须是同一把(同一个对象)
synchronized(this){
    //this代表共享资源
}
public static void test(){
    synchronized(.class)//静态方法字节码
}
4.3.2方式二:同步方法
作用:把访问共享资源的核心方法给上锁,以此保证线程安全
修饰符 synchronized 返回值类型 方法名称(形参列表){
   操作共享资源的代码
}
二者相比:
    范围:同步代码块锁的范围小,同步方法锁的范围更大
    可读性:同步方法更好
4.3.3方式三:Lock锁
Lock是接口,不能直接实例化,可以采用它的实现类ReentrantLock来构建对象
private final Lock lk=new ReentrantLock();
lk.lock;
lk.unlock;
5.线程池
5.1.1线程池概念

线程池是一个可以复用线程的技术。线程池接口:ExecutorService

5.2创建线程池对象
5.2.1方式一:使用ExecutorService的实现类ThreadPoolExecutor创建一个线程池对象
public ThreadPoolExecutor(int corePoolSize(员工),int maximumPooolSize(大学生),long keepAliveTime(空闲多久开除),TimeUnit unit(时间单位),BlockingQueue<Runnable> workQueue(客人排队处),ThreadFactory threadFactory(hr),RejectedExecutionHandler handler(忙不过来咋办))
    
ExecutorService pool=new ThreadPoolExecutor(3,5,10,
            TimeUnit.SECONDS,new LinkedBlockingDeque<>(),Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.AbortPolicy());
    }
注意事项:
    1.临时线程什么时候创建?
新任务提交时发现核心线程都在忙,任务队列也满了,并且还可以创建新的临时线程
    2.什么时候会开始拒绝新任务?
核心线程和临时线程都在忙,任务队列也满了,新的任务才不会被加入
5.2.2方式二:使用Executors(线程池的工具类)调用方法返回不同特点线程池对象
Executors是一个线程池的工具类,提供了很多静态方法用于返回不同特点的线程池对象
//创建固定数量的线程池,如果某个线程执行异常结束,那么会补充一个新线程替代它
public static ExecutorService newFixedThreadPool(int nThtreads)  
//创建只有一个线程的线程池对象,如果该线程出现异常而结束,那么线程池会补充一个新线程
private static void newSingleThreadExecutor() 
//线程数量随任务增加而增加,若线程执行完毕空闲超过60s则会被回收掉
private static  ExecutorService newCachedThreadPool()
//创建一个线程池,可以实现在给定的延迟后运行任务,或者定期执行任务
private  static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
核心线程数量:
1.计算密集型:核心线程数=CPU核数+1   2.IO密集型:核心线程数=CPU核数*2
6.并发与并行

进程概念:正在运行的程序(软件)就是一个独立的进程
线程概念:线程是属于进程的,一个进程中可以有多个线程
进程中的线程是由CPU调度执行的,但CPU同时能处理的线程有限,两个及两个以上的作业在同一 时间段 内执行。
两个及两个以上的作业在同一 时刻 执行。最关键的点是:是否是 同时 执行。

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值