做网站需要的手续,台州手机网站制作,wordpress系列怎么做,简约风格办公室设计1.线程锁
使用Runnable接口和Lambda表达式#xff1a;
在 EasyThreadA 类的 mainA 方法中#xff0c;通过创建 Runnable 实例 run#xff0c;并使用Lambda表达式。 EasyThreadA::method 绑定到 run 上。然后创建两个线程 a 和 b#xff0c;分别启动它们#xff0c;它们会…1.线程锁
使用Runnable接口和Lambda表达式
在 EasyThreadA 类的 mainA 方法中通过创建 Runnable 实例 run并使用Lambda表达式。 EasyThreadA::method 绑定到 run 上。然后创建两个线程 a 和 b分别启动它们它们会并发地执行 method 方法向共享的 list 中添加元素。这里的 list 是一个静态的 ArrayList可能存在线程安全问题。继承Thread类
ThreadA 类继承自 Thread 类重写了 run 方法在其中向自己的 list 中添加元素。在 mainB 方法中创建了两个 ThreadA 实例 a 和 b启动它们分别执行。每个线程拥有独立的 list不存在直接的线程安全问题。实现Runnable接口
RunA 类实现了 Runnable 接口在 run 方法中也向自己的 list 中添加元素。在 main 方法中创建了两个 RunA 实例作为 Thread 的任务分别启动它们。每个 RunA 实例拥有独立的 list不存在直接的线程安全问题。需要注意的知识点多线程的实现方式
可以通过实现 Runnable 接口或者继承 Thread 类来创建线程。推荐优先使用实现 Runnable 接口因为Java中类只能单继承而实现接口可以更灵活地组合多个接口实现不同的功能。线程同步和等待
使用 Thread.sleep(1000) 来模拟线程执行过程中的等待时间。在实际应用中需要根据具体需求使用合适的线程同步机制如 synchronized 关键字、Lock 接口、Atomic 类等来确保线程安全性。Lambda表达式
在 mainA 方法中使用了Lambda表达式 EasyThreadA::method简化了匿名内部类的写法提升了代码的简洁性和可读性。
package com.easy725;import java.util.ArrayList;
import java.util.List;public class EasyThreadA {static List listnew ArrayList();public static void method(){for (int i 0; i 10 ; i) {list.add(iAThread.currentThread().getName());}}public static void mainA(String[] args) {Runnable runEasyThreadA::method;Thread anew Thread(run);Thread bnew Thread(run);a.start();b.start();try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(list.size());}public static void mainB(String[] args) {ThreadA anew ThreadA();ThreadA bnew 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 runnew RunA();Thread anew Thread(run);Thread bnew Thread(run);a.start();b.start();try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(run.list.size());}}
class ThreadA extends Thread{public List listnew ArrayList();Overridepublic void run() {for (int i 0; i 10 ; i) {list.add(a);}}
}
class RunA implements Runnable{public List listnew ArrayList();Overridepublic void run() {for (int i 0; i 10 ; i) {list.add(a);}}
}Lock对象的创建和使用
Lock lock new ReentrantLock();创建了一个 ReentrantLock 类型的锁对象 lock。ReentrantLock 是可重入锁支持公平和非公平性选择默认是非公平锁false。
public void method() 方法中的逻辑 if (lock.tryLock()) {尝试获取锁。如果获取成功返回 true否则打印当前线程名并输出 进入方法然后输出 结束方法最后解锁 lock。 else {如果尝试加锁失败输出 加锁未成功-----去执行别的代码然后通过 Thread.sleep(1000) 模拟执行其他代码的情况随后递归调用 method() 方法再次尝试获取锁。main方法中的线程创建和启动
Runnable run new EasyThreadB()::method;创建一个 Runnable 实例通过方法引用绑定到 EasyThreadB 的 method() 方法上。 Thread a new Thread(run); 和 Thread b new Thread(run);创建两个线程 a 和 b它们共享同一个 run 实例即同一个 method() 方法。 a.start(); 和 b.start();启动两个线程并发执行 method() 方法。需要注意的知识点 Lock接口与ReentrantLock类
Lock 接口提供了比传统的 synchronized 块和方法更广泛的锁定操作。ReentrantLock 是 Lock 接口的实现类具有可重入特性允许线程在同一个线程中多次获取同一个锁避免死锁情况。 tryLock() 方法是 Lock 接口的一部分尝试获取锁如果成功则返回 true否则立即返回 false不会阻塞线程。这在避免线程长时间等待锁的情况下很有用。最后要unLock方法解锁。多线程同步与并发控制
使用 ReentrantLock 可以更精确地控制多线程的并发访问可以在需要的时候尝试获取锁也可以实现公平性或非公平性的锁分配策略。 锁的释放应该始终放在 try 块的 finally 块中以确保即使在获取锁期间发生异常锁也能够被安全地释放。
死锁
进程死锁是指两个或两个以上的进程在执行过程中由于竞争资源或者由于彼此通信而造成的一种阻塞的现象若无外力作用它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁这些永远在互相等待的进程称为死锁进程。
线程死锁是指由于两个或者两个以上的线程互相持有对方所需要的资源导致这些线程处于等待状态无法前往执行。
死锁的产生还涉及到一些具体的条件这些条件可以被看作是死锁产生的必要条件包括
互斥条件资源不能被多个进程或线程同时访问即资源是互斥的。 请求保持条件进程或线程在请求资源时已经持有其他资源并且不愿意释放已经持有的资源。 不可剥夺条件已经分配给进程或线程的资源在未使用完之前不能被其他进程或线程剥夺。 循环等待条件多个进程或线程之间形成一个循环等待链每个进程或线程都在等待链中下一个进程或线程释放资源。
package com.easy725;import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class EasyThreadB {//锁对象 LockLock locknew ReentrantLock();//创建锁对象在中选择是否是公平锁默认false非公平锁。public void method(){//lock.lock();//加锁//lock.trylock() 尝试加锁加锁成功返回true失败返回false。if (lock.tryLock()) {System.out.println(Thread.currentThread().getName() 进入方法);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 runnew EasyThreadB()::method;Thread anew Thread(run);Thread bnew Thread(run);a.start();b.start();}
}读写锁 (ReentrantReadWriteLock) ReentrantReadWriteLock 是一个锁容器包含了读锁和写锁能够提供比普通的互斥锁如 ReentrantLock更高的并发性。 读锁允许多个线程同时获取适合对共享资源进行读取操作。 写锁是排他的只允许一个线程获取用于对共享资源进行写操作。 在代码中通过 rrwl.readLock() 获取读锁通过 rrwl.writeLock() 获取写锁确保对共享资源的安全访问。
线程的启动和执行 使用 Thread 类和 Runnable 接口创建多线程通过 Thread.start() 启动线程实现并发执行多个方法。 在 main 方法中创建了多个读线程和写线程分别调用 method() 和 methodWrite() 方法。线程同步和锁的释放 使用 lock.lock() 和 lock.unlock() 进行锁的获取和释放确保在多线程环境下对共享资源的安全访问。 一般使用 try-finally 块确保在出现异常时能够正确释放锁避免死锁或资源泄漏问题。
package com.easy725;import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;public class EasyThreadC {//ReentrantReadWriteLock是个锁容器public static ReentrantReadWriteLock rrwlnew ReentrantReadWriteLock();public static ReentrantLock rlnew 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) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()方法结束);lock.unlock();}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) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()方法结束);lock.unlock();}public static void main(String[] args) {Runnable runEasyThreadC::method;Runnable runWriteEasyThreadC::methodWrite;Thread anew Thread(run);a.start();Thread bnew Thread(run);b.start();Thread cnew Thread(run);c.start();Thread dnew Thread(run);d.start();Thread enew Thread(run);e.start();Thread fnew Thread(runWrite);f.start();Thread gnew Thread(runWrite);g.start();Thread hnew Thread(runWrite);h.start();Thread inew Thread(runWrite);i.start();System.out.println(main线程结束);}
}同步和对象锁 synchronized 同步块使用 synchronized (OBJ) 对象锁确保多个线程在访问共享资源时的安全性。 wait 和 notify通过 OBJ.wait() 和 OBJ.notify() 方法实现线程的等待和唤醒机制。 wait()使当前线程进入等待状态并释放对象锁直到其他线程调用对象的 notify() 或 notifyAll() 方法唤醒它。 notify() 和 notifyAll()唤醒等待在该对象上的一个或多个线程使它们从等待池中进入就绪状态。线程生命周期和状态 线程等待和重新运行展示了线程如何在 wait() 被调用后进入等待状态并在被唤醒后重新运行。wait和sleep的区别 wait是Object中定义的方法可以由锁对象调用让执行到该代码的线程进入到等待状态。 sleep是Thread类中定义的静态方法也可以让执行到该行的线程进入等待状态。 区别 1.sleep需要传入一个毫秒数到达时间后会自动唤醒。wait不能自动唤醒必须调用notify或者notifyALL方法。 2.sleep方法保持锁状态进入等待状态。wait方法会解除锁状态其他线程可以进入运行。 package com.easy725;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) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()结束同步代码块);OBJ.notify();}}public static void main(String[] args) {Runnable run EasyThreadD::method;Thread anew Thread(run);a.start();Thread bnew Thread(run);b.start();Thread cnew Thread(run);c.start();Thread dnew Thread(run);d.start();}//wait和sleep的区别//wait是Object中定义的方法可以由锁对象调用让执行到该代码的线程进入到等待状态。//sleep是Thread类中定义的静态方法也可以让执行到该行的线程进入等待状态。//区别//1.sleep需要传入一个毫秒数到达时间后会自动唤醒。wait不能自动唤醒必须调用notify或者notifyALL方法。//2.sleep方法保持锁状态进入等待状态。wait方法会解除锁状态其他线程可以进入运行。
}2.线程池
线程池
ThreadPoolExecutor 是 Java 中用于管理线程池的类通过它可以有效地重用线程完成线程的创建管理和销毁工作。 在代码中通过 ThreadPoolExecutor 的构造方法创建了一个线程池 tpe。 在这里使用了一个 ArrayBlockingQueue 作为任务队列 qu它限制了队列的容量为 12。任务提交与执行
线程池可以执行两种类型的任务Runnable 和 Callable。 Runnable run EasyExecuters::method; 定义了一个简单的 Runnable 任务它会调用 method 方法。 tpe.execute(run); 提交 run 任务给线程池执行。 CallableString call EasyExecuters::methodCall; 定义了一个 Callable 任务它会调用 methodCall 方法并返回一个结果。 FutureString f tpe.submit(call); 提交 call 任务给线程池执行并获取一个 Future 对象用于获取任务的执行结果。任务执行结果获取
System.out.println(f.get()); 使用 Future 对象的 get() 方法来获取 call 任务的执行结果。这是一个阻塞方法会等待任务执行完毕并返回结果。线程池的关闭
tpe.shutdown(); 调用 shutdown() 方法关闭线程池。这会使线程池停止接受新的任务并尝试将现有的任务执行完毕后关闭。
package com.easy725;import java.util.Collection;
import java.util.Iterator;
import java.util.Queue;
import java.util.concurrent.*;public class EasyExecuters {//线程池 池重用//完成线程创建管理销毁工作public static void main(String[] args) throws ExecutionException, InterruptedException {BlockingQueue qu new ArrayBlockingQueue(12);ThreadPoolExecutor tpenew ThreadPoolExecutor(5,10,10,TimeUnit.SECONDS,qu,Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());//线程任务RunnableCallableRunnable runEasyExecuters::method;tpe.execute(run);CallableString callEasyExecuters::methodCall;FutureString ftpe.submit(call);//f.cancel(true);//是否取消任务一种中断线程的方式//tpe.submit(run);System.out.println(f.get());//会等待线程执行完毕//关闭线程池对象tpe.shutdown();}public static void method(){System.out.println(Thread.currentThread().getName()执行代码);}public static String methodCall(){System.out.println(Thread.currentThread().getName()执行代码call);return callResult;}
}1. 线程池的七个参数解释 在代码中通过 ThreadPoolExecutor 的构造方法指定了以下七个参数
corePoolSize: 核心线程数即线程池中保持活跃的线程数量即使它们是空闲的也会保留在池中。 maximumPoolSize: 最大线程数线程池中允许的最大线程数量。当活跃线程数达到核心线程数并且工作队列已满时会创建新的线程直到达到这个最大值。 keepAliveTime: 空闲线程的存活时间。超过核心线程数的线程在空闲超过这个时间后会被销毁直到线程池的大小重新变为核心线程数为止。 unit: keepAliveTime 的时间单位。 workQueue: 工作队列用于保存等待执行的任务。在本例中使用了 ArrayBlockingQueue其容量为 12。 threadFactory: 线程工厂用于创建新线程。 handler: 回绝策略用于处理无法执行的任务。在本例中使用了 DiscardPolicy即直接丢弃新任务而不抛出异常。 2.四种回绝策略可以自定义 AbortPolicy默认:放弃该任务并会抛出一个异常RejectedExecutionException。 CallerRunsPolicy:调用者执行让传递任务的线程执行此任务。 DiscardOldestPolicy:放弃队列中时间最长的任务不会抛出异常。 DiscardPolicy直接放弃新的任务不会抛异常。
3. 线程池的工作原理 当任务提交给线程池时线程池会按照以下步骤处理任务 如果当前活跃线程数小于核心线程数创建新的线程来执行任务。 如果当前活跃线程数等于核心线程数将任务加入工作队列。 如果工作队列已满但未达到最大线程数创建新线程来执行任务。占最大线程数 如果工作队列已满且线程数已达到最大值执行指定的回绝策略来处理新任务。
4. 内置的线程池对象 Java 提供了几种常见的内置线程池对象可以根据应用的需要选择合适的线程池
Executors.newCachedThreadPool(): 可根据需要没有空闲就创建新线程的线程池空闲线程会在 60 秒后被回收。 Executors.newFixedThreadPool(int n): 固定大小的线程池可以控制最大线程数。 Executors.newScheduledThreadPool(int corePoolSize): 支持定时和周期性的处理方案。 Executors.newSingleThreadExecutor(): 只有一个线程的线程池确保所有任务按顺序执行。
5. 任务执行与线程池关闭 在代码中通过 execute() 方法提交 Runnable 任务给线程池执行。 最后调用 shutdown() 方法关闭线程池这会使线程池停止接受新任务并尝试将已有的任务执行完毕后关闭。 package com.easy725;import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.*;public class EasyExecutersA {public static void main(String[] args) {//1.说明线程池的七个参数//2.四种回绝策略可以自定义//AbortPolicy默认:放弃该任务并会抛出一个异常RejectedExecutionException。//CallerRunsPolicy:调用者执行让传递任务的线程执行此任务。//DiscardOldestPolicy:放弃队列中时间最长的任务不会抛出异常。//DiscardPolicy直接放弃新的任务不会抛异常。//3.线程池的工作原理// 任务放置在工作队列中//1池中是否有空闲的线程如果有让该线程执行任务。//2如果池中没有空闲的线程判断线程数量是否达到核心线程数。//3如果没有达到创建新的线程执行任务直到填满核心数。如果已经达到优先在队列中存储直到队列填满。//4工作队列填满之后再添加新的任务判断是否达到最大线程数如果没有创建新的线程执行任务直到填满最大线程数。//5如果填满最大线程数队列也已经填满没有空闲的线程就执行回绝策略。//线程池中的线程达到超过核心线程数超出的数量会根据存活时间进行销毁。直到数量达到核心线程数。如果线程的数量少于核心线程数不会消亡。//java中内置的线程池对象//可以根据工作任务创建线程如果没有空闲的线程就创建新的线程。线程存活时间60s。//Executors.newCachedThreadPool();//设定最大线程数量//Executors.newFixedThreadPool(10);//提供定时运行的处理方案//Executors.newScheduledThreadPool(10);//创建一个具有单个线程的线程池保证任务队列完全按照顺序执行//Executors.newSingleThreadExecutor();BlockingQueue queuenew ArrayBlockingQueue(12);ThreadPoolExecutor tpenew ThreadPoolExecutor(5,8,10,TimeUnit.SECONDS,queue,Executors.defaultThreadFactory(),new ThreadPoolExecutor.DiscardPolicy());Runnable run ()-{System.out.println(Thread.currentThread().getName()执行run方法);try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()执行结束);};for (int i 0; i 21 ; i) {tpe.execute(run);}tpe.shutdown();}
}3.枚举
枚举类 默认继承Enum类 首行必须枚举所有的实例。Enum的实例是可比较的根据实例出来的顺序。但是不可序列化不能被new克隆等操作。 当枚举中只有一个实例时这个类就是单例的。
package com.easy725;public enum EasyColor {//枚举类 默认继承Enum类//首行必须枚举所有的实例。Enum的实例是可比较的根据实例出来的顺序。但是不可序列化不能被new克隆等操作。//当枚举中只有一个实例时这个类就是单例的。RED,YELLOW,GREEN,BLUE,PINK;public void printColor(){System.out.println(this.name());System.out.println(this.ordinal());}}
class Test{public static void main(String[] args) {EasyColor.PINK.printColor();}
}