0基础学JAVA(第十天)

1.继承Thread和实现Runnable的区别

线程不安全:

public class EasyThreadA {
    static List list=new ArrayList<>();
    public static void method(){
        for (int i=0;i<10;i++){
           list.add(i+"A"+Thread.currentThread().getName());
        }
        System.out.println(list);
    }

    public static void main(String[] args) {
        Runnable run=EasyThreadA::method;           //Lambda表达式表示可以使用这个放法
                                                      实现当调用run方法的时候使用method代替
        Thread a=new Thread(run);                 
        Thread b=new Thread(run);                  当线程使用的是Runnable中的run方法,那么两 
                                                   个线程公用一个内存
        a.start();
        b.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println(list.size());
    }
}

下面代码中两个主函数,他们分别执行可以看的出一个类继承Thread类的时候,两个线程分别执行操作的是两个不同的内存

但是两个线程共同执行run方法的时候操作的是同一个内存最后的结果汇合在一起

线程安全: 

  public static void main(String[] args) {

        ThreadA a=new ThreadA();
        ThreadA b=new ThreadA();
        a.start();
        b.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println(a.list);
        System.out.println(b.list);
    }
    public static void main(String[] args) {
        RunA runA=new RunA();
        Thread a=new Thread(runA);
        Thread b=new Thread(runA);
        a.start();
        b.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println(runA.list);
        System.out.println(runA.list.size());
    }

}
class ThreadA extends Thread{

    public List list=new ArrayList<>();
    @Override
    public void run() {
        for (int i=0;i<10;i++){
        list.add('a');
    }}
}
class RunA implements Runnable{
    public List list=new ArrayList<>();
    @Override
    public void run() {
        for (int i=0;i<10;i++){
            list.add('a');
        }}


    }

 2.锁对象   Lock

Lock lock=new ReentrantLock();//创建锁对象,非公平锁,但是参数加true就变成公平锁

Reentrant关键字 是可重入的

Lock中主要掌握tryLock   lock   unlock三个方法分别是尝试加锁,但是不一定成功,加锁一定成功,解锁

public class EasyThreadB {
      //锁对象  lock
      Lock lock=new ReentrantLock();//创建锁对象,非公平锁,但是参数加true就变成公平锁
    //Reentrant   可重入的
    public void method() {

        //lock.lock();//加锁
        //trylock  尝试加锁     加锁成功返回true  失败返回false
        if (lock.tryLock()) {
            System.out.println(Thread.currentThread().getName() + "进入方法");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName() + "结束方法");
            lock.unlock();
        }
        else {
            System.out.println("加锁未成功-----去执行别的代码");

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            method();
        }
    }
    public static void main(String[] args) {
        Runnable run=new EasyThreadB()::method;
        Thread a=new Thread(run);
        Thread b=new Thread(run);
        a.start();
        b.start();
    }
}

3.读写锁

读锁是共享锁,不管前面是否结束都可以继续加锁

写锁是独占锁,前一个写锁线程结束才可以加写一个写锁

public class EasyThreadC {
    //读锁是共享锁,不管前面是否结束都可以继续加锁
    //写锁是独占锁,前一个写锁线程结束才可以加写一个写锁
    public static ReentrantReadWriteLock rrwl=new ReentrantReadWriteLock();
    public static ReentrantLock rl=new ReentrantLock();
    public static void method(){
        System.out.println(Thread.currentThread().getName()+"进入方法");
        Lock lock=rrwl.readLock();
        lock.lock();
        System.out.println(Thread.currentThread().getName()+"加锁成功--读锁");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        lock.unlock();
        System.out.println(Thread.currentThread().getName()+"方法结束");

    }

    public static void main(String[] args) {
        Runnable run=EasyThreadC::method;
        Runnable runWrite=EasyThreadC::methodWrite;
        Thread a=new Thread(run);
        Thread b=new Thread(run);

        Thread c=new Thread(run);
        Thread d=new Thread(run);
        a.start();
        b.start();
        c.start();
        d.start();


        Thread e=new Thread(runWrite);
        Thread f=new Thread(runWrite);

        Thread g=new Thread(runWrite);
        Thread h=new Thread(runWrite);
        e.start();
        f.start();
        g.start();
        h.start();
        System.out.println("main线程结束");
    }

    public static void methodWrite(){
        System.out.println(Thread.currentThread().getName()+"进入方法");
        Lock lock=rrwl.writeLock();
        lock.lock();
        System.out.println(Thread.currentThread().getName()+"加锁成功--写锁");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        lock.unlock();
        System.out.println(Thread.currentThread().getName()+"方法结束");

    }
}

 在上面代码结果中可以发现,读锁的时候可以有不同的线程进入一起读锁,但是一旦有一个线程写锁,就不能有其他线程读锁或者写锁

没有读写锁的情况:


public class EasyThreadE {
    public static void main(String[] args) {
        EasyList list=new EasyList();
        Runnable runSize=()->{list.size();};
        Runnable runget=()->{list.get(0);};
        Runnable runadd=()->{list.add(12);};
        list.add(12);
        Thread a=new Thread(runSize);
        Thread b=new Thread(runadd);
        Thread c=new Thread(runget);
        Thread thread=new Thread(runadd);
        a.start();
        b.start();
        thread.start();
    }


}
class EasyList{
    private int[] values=new int[20];
    int size=0;

    ReentrantReadWriteLock rrwl=new ReentrantReadWriteLock();
    public int size(){
        System.out.println(Thread.currentThread().getName()+"Size开始");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println(Thread.currentThread().getName()+"Size结束");
        return size;

    }
    public synchronized int get(int index){
        System.out.println(Thread.currentThread().getName()+"运行get");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        if (index>=size){
        throw new IndexOutOfBoundsException("index is"+index);
    }
        System.out.println(Thread.currentThread().getName()+"---------get结束");
        return values[index];
    }


    public  boolean add(int item){
        System.out.println(Thread.currentThread().getName()+"运行add");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        if (size> values.length-1){
            return false;
        }
        values[size++]=item;
        System.out.println(Thread.currentThread().getName()+"---------add结束");
        return true;
    }
}

4.自定义锁对象

public class EasyThreadD {
    public static final Object OBJ=new Object();//作为锁对象

    public static void method(){
        System.out.println(Thread.currentThread().getName()+"进入方法");

        synchronized (OBJ){

            OBJ.notify();//唤醒一条被该锁对象wait的线程
            //OBJ.notifyAll();唤醒所有被该锁对象wait的线程
            System.out.println(Thread.currentThread().getName()+"进入同步代码块");
            try {
                try {
                    System.out.println(Thread.currentThread().getName()+"进入等待");
                OBJ.wait();//让执行到该行代码的线程进入等待状态(等待池)
                    System.out.println(Thread.currentThread().getName()+"重新运行");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName()+"结束同步代码块");
            OBJ.notify();
        }
    }

    public static void main(String[] args) {
        Runnable run= EasyThreadD::method;
        Thread a=new Thread(run);
        a.start();
        Thread b=new Thread(run);
        b.start();
        Thread c=new Thread(run);
        c.start();
        Thread d=new Thread(run);
        d.start();
    }

wait和sleep的区别:

wait是Object中定义的方法,可以有锁对象调用,让执行到该行代码的线程进入等待状态

sleep是thread中定义的静态方法,可以让执行到该行代码的线程进入等待状态

区别:1. sleep需要传入一个毫秒数,到达时间之后会自动唤醒,

               wait不能自动唤醒,需要调用notify或者notifyAll方法唤醒

           2.sleep方法保持锁状态进入等待状态

               wait方法会解除锁状态,其他线程可以进入运行

5.线程池

线程池,池就是用来重用的

线程池主要用来线程的创建,重用和销毁的工作   

线程池有七个参数:核心线程数,最大线程数,存活时间,时间单位,对象,工作队列,回绝策略

BlockingQueue queue=new ArrayBlockingQueue(12);
        ThreadPoolExecutor t=new ThreadPoolExecutor(5,10,10, TimeUnit.SECONDS,queue,Executors.defaultThreadFactory(),new
                ThreadPoolExecutor.AbortPolicy());

线程池可以用Runnable和Callable

其中Runnable 可以使用submit和excute两个方法启动线程

Callable只能用submit启动线程

使用submit方法的时候会返回一个Future类型所以需要使用Future类建立对象接受返回的值

public class EasyExecuters {
    //池   重用
    //完成线程创建和重用,销毁工作
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //Executors.
        BlockingQueue queue=new ArrayBlockingQueue(12);
        ThreadPoolExecutor t=new ThreadPoolExecutor(5,10,10, TimeUnit.SECONDS,queue,Executors.defaultThreadFactory(),new
                ThreadPoolExecutor.AbortPolicy());

        //线程任务   Runnable  Callable
        Runnable run=EasyExecuters::method;//Runnable可以用excute或者submit
        t.execute(run);


        Callable<String> callable=EasyExecuters::methodCall;//只能用submit
       Future<String> f= t.submit(callable);
        //t.submit(run);
        System.out.println(f.get());//会等待线程执行完毕,然后获取
        //线程池对象需要关闭
        t.shutdown();

    }

    public static void method(){
        System.out.println(Thread.currentThread().getName()+"执行1代码");

    }
    public static String methodCall(){
        System.out.println(Thread.currentThread().getName()+"执行2代码");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return "callResult";
    }
}

1.工作原理:

线程池工作原理
//1.线程池接受任务后任务会放置在工作队列中,首先查看池中是否有空闲的线程,如果有就让该线程执行任务
// 当工作队列填满之后,如果没有空闲线程,然后看有没有达到核心线程数如果没有达到核心线程数,会创建新的线程执行新的任务
//如果池中没有空闲线程,判断线程数量是否达到核心线程数
//如果没有达到,会创建新的线程执行任务,知道填满核心线程数,如果已经达到,有现在都列中存储
//如果队列填满,
//工作队列填满后再添加新的任务,判断是否达到最大线程数,如果没有,创建新的线程执行任务
//知道填满最大线程数,如果已经填满最大线程数,队列也已经填满,没有空闲线程,并没有空闲线程,就执行回绝策略
//线程池中的线程达到核心线程数(或者超过),超出的数量会根据存活时间进行销毁,直到数量达到核心线程数,如果线程的数量少于核心线程数,不会销毁

2.java中内置的线程池对象

java中内置的线程池对象
//1.Executors.newCachedThreadPool()
//可以根据工作任务创建线程,如果没有空闲线程就创建新的线程,线程存活时间60s
//2.Executors.newfixedThreadpool(10)
//设置一个最大线程数量的线程池
//3.Executors.newScheduledThreadPool(10)提供定时运行的处理方案
//4.Executors.newSingleThreadExecutor创建一个具有单个线程的线程池,保障任务队列完全按照顺序顺序执行

3.七个参数

//核心线程数,最大线程数,存活时间,时间单位,对象,工作队列,回绝策略

4.回绝策略

回绝策略 

1.AbortPolicy (默认使用)会抛出异常,会放弃该任务 

2.CallRunsPolicy 当线程无法执行的时候,让传递任务的线程执行此任务 

3.DiscardOldestPolicy (丢弃最久的)放弃队列中时间最长的任务,不会抛出异常,放弃的任务还没有执行 

4.DiscardPolicy (直接放弃新的任务)不会抛出异常

 BlockingQueue queue=new ArrayBlockingQueue(12);
        ThreadPoolExecutor t=new ThreadPoolExecutor(5,8,10, TimeUnit.SECONDS,queue, Executors.defaultThreadFactory(),new ThreadPoolExecutor.DiscardOldestPolicy());



        Runnable run=()->{
            System.out.println(Thread.currentThread().getName()+"执行代码");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName()+"执行ci代码");
        };
        for (int i=0;i<17;i++){
            t.execute(run);
        }
        t.shutdown();
    }

上面代码中在i执行17次之前一直都只有五个线程在执行(五个核心线程,12个任务队列)

在执行第18次之后会加线程,但是最多只能加到8个因为最大数量线程就是8

6.枚举类

在使用枚举类的时候不需要继承Enum类,会默认继承而且加上继承之后会报错

在首行需要写出所有要用到的实例

public enum EasyCorlor {
    //枚举类  默认继承Enum类
    //首行 需要写出所有实例
    RED,YELLOW,GREEN,BLUE,PINK;
    public void printCorlor(){

        System.out.println(this.name());
        System.out.println(this.ordinal());
    }


}
class test{
    public static void main(String[] args) {
        EasyCorlor.RED.printCorlor();
        EasyCorlor.GREEN.printCorlor();
    }
}

在打印中第一个是打印实例的名字,第二个打印在首行中枚举出的实例的位置

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值