您的位置:首页 > 文旅 > 旅游 > 学习Java的第十天(2024.7.25)

学习Java的第十天(2024.7.25)

2024/12/23 10:06:12 来源:https://blog.csdn.net/tuowenjian/article/details/140688883  浏览:    关键词:学习Java的第十天(2024.7.25)

1.线程中的函数式接口

   函数式接口将Runnable接口中的run()方法重写为method()方法,下列代码测试两个线程分别对同一个集合中10个元素,最后获取集合的长度,由于线程不安全,最后集合长度的输出结果会小于20。

    static List list = new ArrayList<>();public static void method(){for (int i=0;i<10;i++){list.add("A"+Thread.currentThread().getName());}}public static void main(String[] args) {Runnable run = EasyThreadA::method;//函数式接口//使用EasyThreadA中的method替换Runnable中的run()方法Thread a = new Thread(run);Thread b = new Thread(run);a.start();b.start();try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(list.size());}

2.两个线程分别存入十个数据到数组中:

先创建一个继承Thread类的子类,在这个类中重写run()方法,使list中存入十个字符"a"。

class ThreadA extends Thread{public List list = new ArrayList();@Overridepublic void run() {for (int i=0;i<10;i++){list.add("a");}}
}

主函数中定义两个线程,使他们分别执行类ThreadA中的run()方法,他们会在两个数组中分别存入十个字符"a"。

    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(a.list);}

 

3.对两次线程对同一对象进行操作:

先创建一个类RunA,这个类实现了Runnable接口,重写run()方法

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

在主函数中创建一个对象 run,创建两个线程,两个线程对象都指向run对象,会对run执行两次

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

 结果如下:

4.锁对象

 锁对象 Lock

Lock lock = new ReentrantLock();//创建锁对象

可以在ReentrantLock()的括号中传入参数,传入参数true这个锁对象就是公平锁,不传入参数或传入false,这个锁就是非公平锁

    Lock lock1 = new ReentrantLock(true);//创建公平锁Lock lock2 = new ReentrantLock(false);//创建非公平锁(默认状态下是非公平锁)

有两个方法:

lock()             加锁

lock.trylock()  尝试加锁,是布尔类型,加锁成功返回true,失败返回false

    public void method(){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();}

5.ReentrantLock中的两把锁

读锁和写锁是在锁盒子(ReentranReadWriteLock)中的两把锁

    public static ReentrantReadWriteLock rrwl = new ReentrantReadWriteLock();public static ReentrantLock rl = new ReentrantLock();

读锁:

ReentrantLock对象的readLock()方法

    public static void main(String[] args) {Runnable run = EasyThreadC::method;Runnable runWrite = EasyThreadC::methodWrite;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();Thread e = new Thread(run);e.start();}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()+"方法结束");}

写锁:

ReentrantLock对象的writeLock()方法

    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);}System.out.println(Thread.currentThread().getName()+"方法结束");lock.unlock();}public static void main(String[] args) {Thread f = new Thread(runWrite);f.start();Thread g = new Thread(runWrite);g.start();Thread h = new Thread(runWrite);h.start();Thread i = new Thread(runWrite);i.start();System.out.println("main线程结束--------");}

6.锁对象的方法

先创建一个锁对象:

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

OBJ.wait();          让执行到该行代码的线程进入等待状态(等待池中等待)

OBJ.notify();        唤醒一条被该锁对象wait的线程

OBJ.notifyAll();    唤醒全部被该锁对象wait的线程

注意:只有锁对象才能调用这三种方法

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();//只有锁对象才能调用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方法被锁对象解除锁状态,其他线程可以介入运行

7.线程池

池的作用:重用

线程池的作用:对线程进行创建和管理,以及销毁线程

创建一个线程池对象:

ThreadPoolExecutor tpe = new ThreadPoolExecutor(,,,,,,);
//括号中要传入7个参数

要传入的参数:

 这七个参数的含义分别为:

 开启线程池:

tpe.execute(run);

关闭线程池:

注意:线程池像输入输出流一样,开启后需要关闭!!!

tpe.shutdown();//结束线程池

8.线程任务:

Runnable和Callable

public class EasyExecuters {public static void main(String[] args) throws ExecutionException, InterruptedException {ArrayBlockingQueue qu = new ArrayBlockingQueue(12);//队列里只能放12个任务ThreadPoolExecutor tpe = new ThreadPoolExecutor(5,//核心线程数10,//最大线程数10,//存活时间TimeUnit.SECONDS,//时间类型qu,//工作队列Executors.defaultThreadFactory(),//工厂new ThreadPoolExecutor.AbortPolicy());//回绝策略Runnable run = EasyExecuters::method;tpe.execute(run);Callable<String> call = EasyExecuters::methodCall;Future<String> f = tpe.submit(call);//tpe.submit(run);System.out.println(f.get());//会等待线程执行完毕tpe.shutdown();//结束线程池}public static void method(){System.out.println(Thread.currentThread().getName()+"执行代码");}public static String methodCall() throws InterruptedException {System.out.println(Thread.currentThread().getName()+"执行代码");Thread.sleep(2000);return "callResult";}
}

9.回绝策略:

回绝策略分为四个 :

1.AbortPolicy(默认的回绝策略)放弃该任务并且会抛出一个异常RejectdExecutionException,只有AbortPolicy回绝策略会抛出异常

2.CallerRunsPolicy 调用者执行,让传递任务的线程执行此任务,不抛出异常

3.DiscardOldestPolicy 放弃队列中时间最长的任务,将新任务加到队列中,不会抛出异常

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

10.线程池的工作原理

<1>池中是否有空闲的线程,如果有就让线程执行任务

<2>当工作队列填满后,如果没有空闲的线程,判断池中的线程数量有没有达到核心线程数

<3>如果没有达到核心线程数,会创建新的线程执行新的任务,直到填满核心线程数。如果已经达到,优先在队列中存储,直到队列填满

<4>工作队列填满之后再添加新的任务,判断是否达到最大线程数,如果没有,创建新的线程执行任务直到填满最大的线程数

<5>已经填满最大线程数,队列也已经填满,没有空闲的线程,就执行回绝策略

11.核心线程数注意点:

1.线程池中的线程达到/超过核心线程数,超出的数量会根据存活时间,进行销毁,直到数量达到核心线程数

2.如果线程的数量少于核心线程数,不会消亡

12.Java中内置的线程池对象:

可以根据工作任务来创建线程,如果没有空闲的线程,就创建新的线程

注意:线程存活时间:60s

Executors.newCachedThreadPool();

Executors.newFixedThreadPool(10);设定最大线程数量的线程池

Executors.newScheduledThreadPool(10);提供定时运行的处理方案(可以延期运行)

Executors.newSingleThreadExecutor();创建一个单个线程的线程池 保障任务队列完全按照顺序执行

public class EasyExecutersA {public static void main(String[] args) {BlockingQueue queue = new ArrayBlockingQueue(12);ThreadPoolExecutor tpe = new ThreadPoolExecutor(5,8,10, TimeUnit.SECONDS,queue,Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());Runnable run = ()->{System.out.println(Thread.currentThread().getName()+"执行代码run");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(Thread.currentThread().getName()+"代码执行完毕");};for (int i=0;i<12;i++){tpe.execute(run);}tpe.shutdown();}
}

13.synchronized和Lock 的实例

Lock:

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(runGet);Thread c=new Thread(runAdd);a.start();b.start();c.start();}
}
class EasyList{private int[] values=new int[20];private int size=0;ReentrantReadWriteLock rwLock=new ReentrantReadWriteLock();public int size(){Lock readLock=rwLock.readLock();readLock.lock();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结束");readLock.unlock();return size;}public int get(int index){Lock readLock=rwLock.readLock();readLock.lock();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结束");readLock.unlock();return values[index];}public  boolean add(int item){Lock writeLock=rwLock.writeLock();writeLock.lock();System.out.println(Thread.currentThread().getName()+"Add开始");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}if(size>=values.length){return false;}values[size++]=item;System.out.println(Thread.currentThread().getName()+"Add结束");writeLock.unlock();return true;}
}

synchronized锁:

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(runGet);Thread c=new Thread(runAdd);a.start();b.start();c.start();}
}
class EasyList{private int[] values=new int[20];private int size=0;ReentrantReadWriteLock rwLock=new ReentrantReadWriteLock();public synchronized 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 synchronized 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){return false;}values[size++]=item;System.out.println(Thread.currentThread().getName()+"Add结束");return true;}
}

14.死锁

死锁:是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去
(1) 因为系统资源不足。
(2) 进程运行推进顺序不合适。
(3) 资源分配不当等。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com