首页 文章 精选 留言 我的

精选列表

搜索[Java],共10000篇文章
优秀的个人博客,低调大师

Java并发编程实战系列10之避免活跃性危险

10.1 死锁 哲学家问题 有环 A等B,B等A 数据库往往可以检测和解决死锁//TODO JVM不行,一旦死锁只有停止重启。 下面分别介绍了几种典型的死锁情况: 10.1.1 Lock ordering Deadlocks 下面是一个经典的锁顺序死锁:两个线程用不同的顺序来获得相同的锁,如果按照锁的请求顺序来请求锁,就不会发生这种循环依赖的情况。 public class LeftRightDeadlock { private final Object left = new Object(); private final Object right = new Object(); public void leftRight() { synchronized (left) { synchronized (right) { doSomething(); } } } public void rightLeft() { synchronized (right) { synchronized (left) { doSomethingElse(); } } } void doSomething() { } void doSomethingElse() { } } 10.1.1 Dynamic Lock Order Deadlocks 下面的转账例子,如果一个线程X向Y转,而另外一个线程Y向X也转,那么就会发生死锁。 public class DynamicOrderDeadlock { // Warning: deadlock-prone! public static void transferMoney(Account fromAccount, Account toAccount, DollarAmount amount) throws InsufficientFundsException { synchronized (fromAccount) { synchronized (toAccount) { if (fromAccount.getBalance().compareTo(amount) < 0) throw new InsufficientFundsException(); else { fromAccount.debit(amount); toAccount.credit(amount); } } } } static class DollarAmount implements Comparable<DollarAmount> { // Needs implementation public DollarAmount(int amount) { } public DollarAmount add(DollarAmount d) { return null; } public DollarAmount subtract(DollarAmount d) { return null; } public int compareTo(DollarAmount dollarAmount) { return 0; } } static class Account { private DollarAmount balance; private final int acctNo; private static final AtomicInteger sequence = new AtomicInteger(); public Account() { acctNo = sequence.incrementAndGet(); } void debit(DollarAmount d) { balance = balance.subtract(d); } void credit(DollarAmount d) { balance = balance.add(d); } DollarAmount getBalance() { return balance; } int getAcctNo() { return acctNo; } } static class InsufficientFundsException extends Exception { } } 解决办法还是顺序话锁,考虑针对两种情况取hashcode然后判断if-else里面决定锁顺序。 class Helper { public void transfer() throws InsufficientFundsException { if (fromAcct.getBalance().compareTo(amount) < 0) throw new InsufficientFundsException(); else { fromAcct.debit(amount); toAcct.credit(amount); } } } int fromHash = System.identityHashCode(fromAcct); int toHash = System.identityHashCode(toAcct); if (fromHash < toHash) { synchronized (fromAcct) { synchronized (toAcct) { new Helper().transfer(); } } } else if (fromHash > toHash) { synchronized (toAcct) { synchronized (fromAcct) { new Helper().transfer(); } } } else { synchronized (tieLock) { synchronized (fromAcct) { synchronized (toAcct) { new Helper().transfer(); } } } } 10.1.3 在协作对象之间发生死锁Deadlocks Between Cooperating Objects 下面的例子setLocation和getImage都会获取两把锁,会存在两个线程按照不同的顺序获取锁的情况。 public class CooperatingDeadlock { // Warning: deadlock-prone! class Taxi { @GuardedBy("this") private Point location, destination; private final Dispatcher dispatcher; public Taxi(Dispatcher dispatcher) { this.dispatcher = dispatcher; } public synchronized Point getLocation() { return location; } public synchronized void setLocation(Point location) { this.location = location; if (location.equals(destination)) dispatcher.notifyAvailable(this); } public synchronized Point getDestination() { return destination; } public synchronized void setDestination(Point destination) { this.destination = destination; } } class Dispatcher { @GuardedBy("this") private final Set<Taxi> taxis; @GuardedBy("this") private final Set<Taxi> availableTaxis; public Dispatcher() { taxis = new HashSet<Taxi>(); availableTaxis = new HashSet<Taxi>(); } public synchronized void notifyAvailable(Taxi taxi) { availableTaxis.add(taxi); } public synchronized Image getImage() { Image image = new Image(); for (Taxi t : taxis) image.drawMarker(t.getLocation()); return image; } } class Image { public void drawMarker(Point p) { } } } 10.1.4 开放调用 减小锁的力度,锁不嵌套。 class CooperatingNoDeadlock { @ThreadSafe class Taxi { @GuardedBy("this") private Point location, destination; private final Dispatcher dispatcher; public Taxi(Dispatcher dispatcher) { this.dispatcher = dispatcher; } public synchronized Point getLocation() { return location; } public synchronized void setLocation(Point location) { boolean reachedDestination; synchronized (this) { this.location = location; reachedDestination = location.equals(destination); } if (reachedDestination) dispatcher.notifyAvailable(this); } public synchronized Point getDestination() { return destination; } public synchronized void setDestination(Point destination) { this.destination = destination; } } @ThreadSafe class Dispatcher { @GuardedBy("this") private final Set<Taxi> taxis; @GuardedBy("this") private final Set<Taxi> availableTaxis; public Dispatcher() { taxis = new HashSet<Taxi>(); availableTaxis = new HashSet<Taxi>(); } public synchronized void notifyAvailable(Taxi taxi) { availableTaxis.add(taxi); } public Image getImage() { Set<Taxi> copy; synchronized (this) { copy = new HashSet<Taxi>(taxis); } Image image = new Image(); for (Taxi t : copy) image.drawMarker(t.getLocation()); return image; } } class Image { public void drawMarker(Point p) { } } } 1.0.15 资源死锁 数据库连接池,A持有数据库D1连接,等待与D2连接,B持有D2的连接,等待与D1连接。 线程饥饿死锁,如8.1.1小节的例子。 10.2 死锁的避免与诊断 10.2.1 支持定时的锁 tryLock 10.2.2 kill -3 发信号给JVM dump线程 10.3 其他活跃性危险 10.3.1 饥饿 10.3.3 活锁Livelock 他不会阻塞线程,但是也不能继续执行,因为线程在不断的重复执行相同的操作,而且总会失败。 例如处理事务消,回滚后再次重新把任务放在队头。 又例如发送数据包,都选择1s后重试,那么总会冲突,所以可以考虑一个随机数时间间隔。

优秀的个人博客,低调大师

Java并发编程实战系列8之线程池的使用

ThreadPoolExecutor UML图: image image 8.1 在任务和执行策略之间隐形耦合 避免Thread starvation deadlock 8.2 设置线程池大小 8.3 配置ThreadPoolExecutor image 构造函数如下: public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { ... } 核心和最大池大小:如果运行的线程少于 corePoolSize,则创建新线程来处理请求(即一个Runnable实例),即使其它线程是空闲的。如果运行的线程多于 corePoolSize 而少于 maximumPoolSize,则仅当队列满时才创建新线程。 保持活动时间:如果池中当前有多于 corePoolSize 的线程,则这些多出的线程在空闲时间超过 keepAliveTime 时将会终止。 排队:如果运行的线程等于或多于 corePoolSize,则 Executor 始终首选将请求加入队列BlockingQueue,而不添加新的线程。 被拒绝的任务:当 Executor 已经关闭,或者队列已满且线程数量达到maximumPoolSize时(即线程池饱和了),请求将被拒绝。这些拒绝的策略叫做Saturation Policy,即饱和策略。包括AbortPolicy, CallerRunsPolicy, DiscardPolicy, and DiscardOldestPolicy. 另外注意: 如果运行的线程少于 corePoolSize,ThreadPoolExecutor 会始终首选创建新的线程来处理请求;注意,这时即使有空闲线程也不会重复使用(这和数据库连接池有很大差别)。 如果运行的线程等于或多于 corePoolSize,则 ThreadPoolExecutor 会将请求加入队列BlockingQueue,而不添加新的线程(这和数据库连接池也不一样)。 如果无法将请求加入队列(比如队列已满),则创建新的线程来处理请求;但是如果创建的线程数超出 maximumPoolSize,在这种情况下,请求将被拒绝。 newCachedThreadPool使用了SynchronousQueue,并且是无界的。 线程工厂ThreadFactory 8.4 扩展ThreadPoolExecutor 重写beforeExecute和afterExecute方法。 8.5 递归算法的并行化 实际就是类似Number of Islands或者N-Queens等DFS问题的一种并行处理。 串行版本如下: public class SequentialPuzzleSolver <P, M> { private final Puzzle<P, M> puzzle; private final Set<P> seen = new HashSet<P>(); public SequentialPuzzleSolver(Puzzle<P, M> puzzle) { this.puzzle = puzzle; } public List<M> solve() { P pos = puzzle.initialPosition(); return search(new PuzzleNode<P, M>(pos, null, null)); } private List<M> search(PuzzleNode<P, M> node) { if (!seen.contains(node.pos)) { seen.add(node.pos); if (puzzle.isGoal(node.pos)) return node.asMoveList(); for (M move : puzzle.legalMoves(node.pos)) { P pos = puzzle.move(node.pos, move); PuzzleNode<P, M> child = new PuzzleNode<P, M>(pos, move, node); List<M> result = search(child); if (result != null) return result; } } return null; } } 并行版本如下: public class ConcurrentPuzzleSolver <P, M> { private final Puzzle<P, M> puzzle; private final ExecutorService exec; private final ConcurrentMap<P, Boolean> seen; protected final ValueLatch<PuzzleNode<P, M>> solution = new ValueLatch<PuzzleNode<P, M>>(); public ConcurrentPuzzleSolver(Puzzle<P, M> puzzle) { this.puzzle = puzzle; this.exec = initThreadPool(); this.seen = new ConcurrentHashMap<P, Boolean>(); if (exec instanceof ThreadPoolExecutor) { ThreadPoolExecutor tpe = (ThreadPoolExecutor) exec; tpe.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy()); } } private ExecutorService initThreadPool() { return Executors.newCachedThreadPool(); } public List<M> solve() throws InterruptedException { try { P p = puzzle.initialPosition(); exec.execute(newTask(p, null, null)); // block until solution found PuzzleNode<P, M> solnPuzzleNode = solution.getValue(); return (solnPuzzleNode == null) ? null : solnPuzzleNode.asMoveList(); } finally { exec.shutdown(); } } protected Runnable newTask(P p, M m, PuzzleNode<P, M> n) { return new SolverTask(p, m, n); } protected class SolverTask extends PuzzleNode<P, M> implements Runnable { SolverTask(P pos, M move, PuzzleNode<P, M> prev) { super(pos, move, prev); } public void run() { if (solution.isSet() || seen.putIfAbsent(pos, true) != null) return; // already solved or seen this position if (puzzle.isGoal(pos)) solution.setValue(this); else for (M m : puzzle.legalMoves(pos)) exec.execute(newTask(puzzle.move(pos, m), m, this)); } } }

优秀的个人博客,低调大师

Java中方法重写的两个面试题

1:方法重写和方法重载的区别?方法重载能改变返回值类型吗? 方法重写: 在子类中,出现和父类中一模一样的方法声明的现象。(包含方法名、参数列表和返回值类型都一样) 方法重载: 同一个类中,出现的方法名相同,参数列表不同,与返回值类型无关的现象。 方法重载能改变返回值类型,因为它和返回值类型无关。 Override:方法重写 Overload:方法重载 2:this关键字和super关键字分别代表什么?以及他们各自的使用场景和作用。 this: 代表当前类的对象引用。 super:代表父类存储空间的标识。(可以理解为父类的引用,通过这个东西可以访问父类的成员。) 应用场景: 成员变量: this.成员变量 super.成员变量 构造方法: this(...) super(...) 成员方法: this.成员方法 super.成员方法我的GitHub地址: https://github.com/heizemingjun 我的博客园地址: http://www.cnblogs.com/chenmingjun 我的蚂蚁笔记博客地址: http://blog.leanote.com/chenmingjun Copyright ©2018 黑泽明军 【转载文章务必保留出处和署名,谢谢!】

优秀的个人博客,低调大师

Java并发编程实战系列6之任务执行(Task Execution)

1. 在线程中执行任务 1.1 串行的执行任务 这是最经典的一个最简单的Socket server的例子,服务器的资源利用率非常低,因为单线程在等待I/O操作完成时,CPU处于空闲状态。从而阻塞了当前请求的延迟,还彻底阻止了其他等待中的请求被处理。 public class SingleThreadWebServer { public static void main(String[] args) throws IOException { ServerSocket socket = new ServerSocket(80); while (true) { Socket connection = socket.accept(); handleRequest(connection); } } private static void handleRequest(Socket connection) { // request-handling logic here } } 1.2 显式地为任务创建线程 任务处理从主线程中分离出来,主循环可以快速等待下一个连接,提高响应性。同时任务可以并行处理了,吞吐量也提高了。 public class ThreadPerTaskWebServer { public static void main(String[] args) throws IOException { ServerSocket socket = new ServerSocket(80); while (true) { final Socket connection = socket.accept(); Runnable task = new Runnable() { public void run() { handleRequest(connection); } }; new Thread(task).start(); } } private static void handleRequest(Socket connection) { // request-handling logic here } } 1.3 无限制创建线程的不足 线程的生命周期开销非常高 资源消耗。大量的空闲线程占用内存,给GC带来压力,同时线程数量过多,竞争CPU资源开销太大。 稳定性。容易引起GC问题,甚至OOM 2 Executor框架 任务就是一组逻辑工作单元(unit of work),而线程则是使任务异步执行的机制。 Executor接口,是代替Thread来做异步执行的入口,接口虽然简单,却为非常灵活强大的异步任务执行框架提供了基础。 提供了一种标准的方法将任务的提交与执行过程解耦,并用Runnable(无返回时)或者Callable(有返回值)表示任务。 Executor基于生产者-消费者模式 提交任务/执行任务分别相当于生产者/消费者,通常是最简单的实现生产者-消费者设计的方式了 2.1 基于Executor改造后的样例如下 将请求处理任务的提交与任务的实际执行解耦,并且只需采用另一种不同的Executor实现,就可以改变服务器的行为,其影响远远小于修改任务提交方式带来的影响 2.2 执行策略 这一节主要介绍做一个Executor框架需要靠那些点? 在什么线程中执行任务? 任务按照什么顺序执行?FIFO/LIFO/优先级 有多少个任务可以并发执行? 队列中允许多少个任务等待? 如果系统过载了要拒绝一个任务,那么选择拒绝哪一个?如何通知客户端任务被拒绝了? 在执行任务过程中能不能有些别的动作before/after或者回调? 各种执行策略都是一种资源管理工具,最佳的策略取决于可用的计算资源以及对服务质量的要求。 因此每当看到 new Thread(runnable).start(); 并且希望有一种灵活的执行策略的时候,请考虑使用Executor来代替 2.3 线程池 在线程池中执行任务比为每个任务分配一个线程优势明显: 重用线程,减少开销。 延迟低,线程是等待任务到达。 最大化挖掘系统资源以及保证稳定性。CPU忙碌但是又不会出现线程竞争资源而耗尽内存或者失败的情况。 Executors可以看做一个工厂,提供如下几种Executor的创建: newCachedThreadPool newFixedThreadPool newSingleThreadExecutor newScheduledThreadPool 2.4 Executor的生命周期 为解决执行服务的生命周期问题,Executor扩展了ExecutorService接口,添加了一些用于生命周期管理的方法 一个优雅停止的例子: 增加生命周期扩展Web服务器的功能 调用stop 客户端请求形式 关闭 2.5 延迟任务与周期任务 使用Timer的弊端在于 如果某个任务执行时间过长,那么将破坏其他TimerTask的定时精确性(执行所有定时任务时只会创建一个线程),只支持基于绝对时间的调度机制,所以对系统时钟变化敏感 TimerTask抛出未检查异常后就会终止定时线程(不会捕获异常) 更加合理的做法是使用ScheduledThreadPoolExecutor,只支持基于相对时间的调度 它是DelayQueue的应用场景 3 找出可利用的并行性 3.1 携带结果的任务Callable和Future Executor框架支持Runnable,同时也支持Callable(它将返回一个值或者抛出一个异常) 在Executor框架中,已提交但是尚未开始的任务可以取消,但是对于那些已经开始执行的任务,只有他们能响应中断时,才能取消。 Future非常实用,他的API如下 内部get的阻塞是靠LockSupport.park来做的,在任务完成后Executor回调finishCompletion方法会依次唤醒被阻塞的线程。 ExecutorService的submit方法接受Runnable和Callable,返回一个Future。ThreadPoolExecutor框架留了一个口子,子类可以重写newTaskFor来决定创建什么Future的实现,默认是FutureTask类。 3.2 示例:使用Future实现页面的渲染器 3.3 CompletionService: Executor与BlockingQueue 计算完成后FutureTask会调用done方法,而CompletionService集成了FutureTask,对于计算完毕的结果直接放在自己维护的BlockingQueue里面,这样上层调用者就可以一个个take或者poll出来。 3.3 示例:使用CompletionService提高渲染性能 void renderPage(CharSequence source) { final List<ImageInfo> info = scanForImageInfo(source); CompletionService<ImageData> completionService = new ExecutorCompletionService<ImageData>(executor); for (final ImageInfo imageInfo : info) completionService.submit(new Callable<ImageData>() { public ImageData call() { return imageInfo.downloadImage(); } }); renderText(source); try { for (int t = 0, n = info.size(); t < n; t++) { Future<ImageData> f = completionService.take(); ImageData imageData = f.get(); renderImage(imageData); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } catch (ExecutionException e) { throw launderThrowable(e.getCause()); } } 6.3.7 为任务设置时限 Future的get支持timeout。 6.3.8 批量提交任务 使用invokeAll方法提交List<Callable>,返回一个List<Future>

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册