JAVA学习DAY-14

一、进程线程

进程(process)是操作系统的任务单元,每一个程序启动后操作系统都会为其分配进程编号(PID)

线程(Thread)是进程中的任务单元,程序启动的时候,首先会创建主线程,可以在主线程中开辟子线程,每一个线程都对应一个虚拟机栈,栈区是线程私有的,堆和方法区是线程共享的

串行

        在一台机器上单线程执行

并行

        并发:在同一台机器上多线程并行执行(存在资源竞争关系

        并行:在多台机器上并行执行(不存在资源竞争关系

二、JAVA中实现多线程的方式--4种

1.继承Thread类,重写run方法

2.实现Runnable接口,重写run方法

3.实现Callable接口,重写call方法

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class Demo03 {
    public static void main(String[] args) {
        MyCallable mc = new MyCallable();   //创建一个Callable对象
        FutureTask<Integer> ft = new FutureTask<>(mc);      //创建一个FutureTask对象,用Callable对象作为构造方法的参数
        Thread t = new Thread(ft);      //创建一个Thread对象,用FutureTask对象作为构造方法的参数
        t.start();

        //Integer sum = ft.get();   会阻塞主线程
        //用FutureTask对象的get()方法取子线程call方法的返回值
        while (true){
            try{
                if(ft.isDone()){        //isDone()方法可以判定子线程有没有运行结束
                    Integer sum = ft.get();   //在取子线程返回值的时候,子线程可以正常返回也可以异常返回
                    System.out.println("子线程返回值:" + sum);
                    break;
                }else {
                    System.out.println("子线程未结束");
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    //静态内部类
    //实现线程的方式3:实现Callable接口,重写call方法
    //需要指定泛型,这个泛型是作为子线程返回值的数据类型
    //实现线程的方式1和方式2都无法实现子线程运行后返回一个结果,因为run()方法的返回值类型是void
    static class MyCallable implements Callable<Integer> {

        @Override
        public Integer call() throws Exception {
            Integer sum = 0;
            for (int i = 0; i < 100; i++) {
                sum += i;
                Thread.sleep(100);
            }
            return sum;
        }
    }
}

 

4.实现线程池类

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Demo04 {
    static final int CORE_POOL_SIZE = 5;    //核心线程数
    static final int MAX_POOL_SIZE = 10;     //最大线程数
    static final int QUEUE_CAPACITY = 100;  //队列容量
    static final long KEEP_ALIVE_TIME = 1L; //存活时间

    static ThreadPoolExecutor executor = null;  //静态指针
    static {
        //初始化线程池对象
         executor = new ThreadPoolExecutor(
                CORE_POOL_SIZE,
                MAX_POOL_SIZE,
                KEEP_ALIVE_TIME,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(QUEUE_CAPACITY),
                new ThreadPoolExecutor.CallerRunsPolicy()
        );
    }


    public static void main(String[] args) {
        Runnable runnable = new myRunnable();
        for (int i = 0; i < 100; i++) {
            //executor是线程池指针,execute是线程池方法,参数是一个runnable
            executor.execute(runnable);
        }
    }

    static class myRunnable implements Runnable{

        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName());
        }
    }
}

 

区别:

方式1,2区别

当一个类已经有父类了,此时不方便继承Thread,可以采用实现Runnable接口的方式,Runnable共享资源也方便。

方式1,2和方式3的区别

方式1,2没有返回值,而且子线程出异常主线程捕捉不到,而方式3可以解决

三、线程的生命周期

 

 

四、锁和死锁

锁是Java中用来保证线程操作原子性的一种机制

锁是数据库中用来保证事务操作原子性的一种机制

锁可以避免脏读

Java中的锁有:synchronized和lock锁

synchronized是关键字,可以锁代码块,也可以锁方法

lock是类(官方推荐),只能锁代码块

 上锁方式1:synchronized

 上锁方式2:lock锁 

 

 

 

产生死锁的条件(原因)

1.互斥条件:锁要具有排他性,在同一时刻锁只能被一个线程持有

2.请求与保持条件:一个线程因为请求其他资源被阻塞的时候,对已获取的资源保持不释放

 3.不剥夺条件:一个线程没有主动释放资源之前,是不能被其他线程强行剥夺的

4.循环等待条件:A线程持有资源a的锁,B线程持有资源b的锁,在互相不释放自己持有的锁的情况下,去请求对方持有的锁,这时候会形成双方循环等待,造成永久阻塞

如何解决死锁

破坏任意一个条件即可

1.破坏互斥条件:用共享锁,在同一时刻,锁可以被多个线程持有

2.破坏请求与保持条件:一次性申请所有的资源

3.破坏不剥夺条件:一个线程因为请求其他资源被阻塞的时候,主动释放已获取的资源

4.破坏循环等待条件:所有线程按照同样的顺序请求资源即可

 

五、线程安全类型和线程不安全类型

 我们把数据类型分为线程安全类型和线程不安全类型

如果一个数据类型需要我们自己手动加锁来保证其操作的原子性,那么他就是线程不安全的数据类型。

如果一个数据类型能够自己在方法中加锁,来保证其操作的原子性,那么他就是线程安全的数据类型。

线程不安全线程安全
ArrayList1.Vector  2.CopyOnWriteArrayList
        HashMap        1.Hashtable  2.ConcurrentHashMap
String,StringBuilder

StringBuffer

int,IntegerAtomicInteger
其他。。。。。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值