- 浏览: 2653199 次
- 来自: 杭州
文章分类
- 全部博客 (1188)
- webwork (4)
- 网摘 (18)
- java (103)
- hibernate (1)
- Linux (85)
- 职业发展 (1)
- activeMQ (2)
- netty (14)
- svn (1)
- webx3 (12)
- mysql (81)
- css (1)
- HTML (6)
- apache (3)
- 测试 (2)
- javascript (1)
- 储存 (1)
- jvm (5)
- code (13)
- 多线程 (12)
- Spring (18)
- webxs (2)
- python (119)
- duitang (0)
- mongo (3)
- nosql (4)
- tomcat (4)
- memcached (20)
- 算法 (28)
- django (28)
- shell (1)
- 工作总结 (5)
- solr (42)
- beansdb (6)
- nginx (3)
- 性能 (30)
- 数据推荐 (1)
- maven (8)
- tonado (1)
- uwsgi (5)
- hessian (4)
- ibatis (3)
- Security (2)
- HTPP (1)
- gevent (6)
- 读书笔记 (1)
- Maxent (2)
- mogo (0)
- thread (3)
- 架构 (5)
- NIO (5)
- 正则 (1)
- lucene (5)
- feed (4)
- redis (17)
- TCP (6)
- test (0)
- python,code (1)
- PIL (3)
- guava (2)
- jython (4)
- httpclient (2)
- cache (3)
- signal (1)
- dubbo (7)
- HTTP (4)
- json (3)
- java socket (1)
- io (2)
- socket (22)
- hash (2)
- Cassandra (1)
- 分布式文件系统 (5)
- Dynamo (2)
- gc (8)
- scp (1)
- rsync (1)
- mecached (0)
- mongoDB (29)
- Thrift (1)
- scribe (2)
- 服务化 (3)
- 问题 (83)
- mat (1)
- classloader (2)
- javaBean (1)
- 文档集合 (27)
- 消息队列 (3)
- nginx,文档集合 (1)
- dboss (12)
- libevent (1)
- 读书 (0)
- 数学 (3)
- 流程 (0)
- HBase (34)
- 自动化测试 (1)
- ubuntu (2)
- 并发 (1)
- sping (1)
- 图形 (1)
- freemarker (1)
- jdbc (3)
- dbcp (0)
- sharding (1)
- 性能测试 (1)
- 设计模式 (2)
- unicode (1)
- OceanBase (3)
- jmagick (1)
- gunicorn (1)
- url (1)
- form (1)
- 安全 (2)
- nlp (8)
- libmemcached (1)
- 规则引擎 (1)
- awk (2)
- 服务器 (1)
- snmpd (1)
- btrace (1)
- 代码 (1)
- cygwin (1)
- mahout (3)
- 电子书 (1)
- 机器学习 (5)
- 数据挖掘 (1)
- nltk (6)
- pool (1)
- log4j (2)
- 总结 (11)
- c++ (1)
- java源代码 (1)
- ocr (1)
- 基础算法 (3)
- SA (1)
- 笔记 (1)
- ml (4)
- zokeeper (0)
- jms (1)
- zookeeper (5)
- zkclient (1)
- hadoop (13)
- mq (2)
- git (9)
- 问题,io (1)
- storm (11)
- zk (1)
- 性能优化 (2)
- example (1)
- tmux (1)
- 环境 (2)
- kyro (1)
- 日志系统 (3)
- hdfs (2)
- python_socket (2)
- date (2)
- elasticsearch (1)
- jetty (1)
- 树 (1)
- 汽车 (1)
- mdrill (1)
- 车 (1)
- 日志 (1)
- web (1)
- 编译原理 (1)
- 信息检索 (1)
- 性能,linux (1)
- spam (1)
- 序列化 (1)
- fabric (2)
- guice (1)
- disruptor (1)
- executor (1)
- logback (2)
- 开源 (1)
- 设计 (1)
- 监控 (3)
- english (1)
- 问题记录 (1)
- Bitmap (1)
- 云计算 (1)
- 问题排查 (1)
- highchat (1)
- mac (3)
- docker (1)
- jdk (1)
- 表达式 (1)
- 网络 (1)
- 时间管理 (1)
- 时间序列 (1)
- OLAP (1)
- Big Table (0)
- sql (1)
- kafka (1)
- md5 (1)
- springboot (1)
- spring security (1)
- Spring Boot (3)
- mybatis (1)
- java8 (1)
- 分布式事务 (1)
- 限流 (1)
- Shadowsocks (0)
- 2018 (1)
- 服务治理 (1)
- 设计原则 (1)
- log (0)
- perftools (1)
最新评论
-
siphlina:
课程——基于Python数据分析与机器学习案例实战教程分享网盘 ...
Python机器学习库 -
san_yun:
leibnitz 写道hi,我想知道,无论在92还是94版本, ...
hbase的行锁与多版本并发控制(MVCC) -
leibnitz:
hi,我想知道,无论在92还是94版本,更新时(如Puts)都 ...
hbase的行锁与多版本并发控制(MVCC) -
107x:
不错,谢谢!
Latent Semantic Analysis(LSA/ LSI)算法简介 -
107x:
不错,谢谢!
Python机器学习库
1, 为什么wait与notify之前必须要加synchronized?
答案其实很简单,也是为了防止等待-通知机制出现race condition
为什么会出现race condition ?
答: 对象在被wait之前已经被另一线程notify , 之后的wait 会永久停止,并导致deadlock(死锁)
理想情况:
1, 第一个线程判断该对象是否要wait
2, 第一个线程将对象wait
3, 第二个线程再将对象notify
实际情况
1, 第一个线程判断该对象是否要wait
2, 第二个线程将对象notify
3, 第一个线程将对象wait
为了防止这些情况,才需要在wait与notify之前加synchronized
java 代码
A a = A.getInstance ( ) ; //单例对象,同一份实例不销毁 synchronized ( a) { a.wait ( ) ; } ------------------------------- 另一线程 A a = A.getInstance ( ) ; synchronized ( a) { a.notify ( ) ; }
等待-通知机制必须与sychronized一起用,否则自身也会有 race condition.
2, 静态同步方法与非静态同步方法的区别
有时,我们经常会碰到这样的代码!
业务逻辑的封装类:
public class Logic { private static final Log log = LogFactory.getLog ( Logic.class ) ; private static Logic logic; private Logic( ) { } public static Logic getInstance( ) { if ( null == logic) { logic = new Logic( ) ; } return logic; } public static synchronized void testStatic( ) { log.info ( Thread .currentThread ( ) .getName ( ) + " : static method is running" ) ; } public synchronized void testNonStatic( ) { log.info ( Thread .currentThread ( ) .getName ( ) + " : non static method is running" ) ; } }
非静态方法的执行:
public class ThreadRun1 extends Thread { private static final Log log = LogFactory.getLog ( ThreadRun1.class ) ; public void run( ) { Logic logic = Logic.getInstance ( ) ; // object reference try { Thread .sleep ( 3000 ) ; } catch ( InterruptedException e) { log.error ( "some exceptions occured :" , e) ; } logic.testNonStatic ( ) ; logEnd( ) ; } private void logEnd( ) { log.info ( "thread run1 end" ) ; } }
静态类方法的执行
public class ThreadRun2 extends Thread { private static final Log log = LogFactory.getLog ( ThreadRun1.class ) ; public void run( ) { Logic.testStatic ( ) ; // class static reference try { Thread .sleep ( 5000 ) ; } catch ( InterruptedException e) { log.error ( "some error ocuur :" , e) ; } logEnd( ) ; } private void logEnd( ) { log.info ( "thread run2 end" ) ; } }
测试类
public class TestThread { /** * @param args */ public static void main( String [ ] args) { ThreadRun1 run1 = new ThreadRun1( ) ; run1.start ( ) ; ThreadRun2 run2 = new ThreadRun2( ) ; run2.start ( ) ; } }
现在有2根线程,其中一根会调用testStatic() , 而另一根会在testStatic未执行结束前调用testNonStatic!
那么,按照多线程同步原则,该对象会在调用testStatic()方法时被锁定,而该方法未结束前如果调用testNonStatic()方法,则必须要等待第一个线程执行完后,才可以执行继续执行!
但是,实际情况是两线程可同时被调用!
区别在于,前者是静态的,不需要实例化即可调用,那么既然连实例化的对象都没创建,何来锁住对象呢!
大家都知道,静态的方法一般都是直接调用“类.方法”来执行的,因此,调用testStatic锁住的其实是类!(锁住类不等于锁住该类实例的对象!)
总结:每个class只有一个线程可以执行静态同步方法,每个类的对象,只有一个线程可以执行同步方法!当对象实例调用同步方法,而同步方法中又调用了class的静态同步方法,其实此次调用一共锁住了2个不同的对象监视器!
Class级别的锁与Object级别的锁是不一样的, 两者相互独立
3, thread 的 join 方法与 isAlive 方法的区别.
java 代码
log.info ( "current thread running" ) ; thread1.join ( ) ; // 当前线程在执行到join方法后, 会被block住 , 直到thread1线程处理结束或死亡 log.info ( "current thread stopping" ) ;
java 代码
log.info ( "current thread running" ) ; thread1.isAlive ( ) ; // 直接返回true or false log.info ( "current thread stopping" ) ;
join方法是使当前线程阻塞,直到引用的线程结束才激活.
4, wait-notify机制
在一个以上的thread wait住时,调用notify是随机的唤醒某一thread.
而notifyAll则是唤醒所有等待的线程, 但只有一个线程可以在唤醒后lock object monitor,
所以, notifyAll操作也是有利弊的.
wait-notify机制, 单次唤醒是随机的, 全部唤醒则会导致大部分线程阻塞.
8, Lock接口替代synchronized
a, Lock接口可以比sychronized提供更广泛的锁定操作.可以提供多把不同的锁.且锁之间互不干涉.
b, Lock接口提供lock()与unlock()方法, 使用明确调用来完成同步的, OO思想好于前者.
c, Lock可以自由操控同步范围(scope).
d, Lock接口支持nested lock(嵌套锁定).并提供了丰富的api.
e, Lock接口提供了tryLock()方法, 支持尝试取得某个object lock.
5, Condition替代wait与notify
// 生产/消费者模式 public class Basket { Lock lock = new ReentrantLock( ) ; //产生Condition对象 Condition produced = lock.newCondition ( ) ; Condition consumed = lock.newCondition ( ) ; boolean available = false ; public void produce( ) throws InterruptedException { lock.lock ( ) ; try { if ( available) { produced.await ( ) ; //放弃lock进入睡眠 } System .out .println ( "Apple produced." ) ; available = true ; consumed.signal ( ) ; //发信号唤醒等待这个Condition的线程 } finally { lock.unlock ( ) ; } } public void consume( ) throws InterruptedException { lock.lock ( ) ; try { if ( ! available) { consumed.await ( ) ; //放弃lock进入睡眠 } /*吃苹果*/ System .out .println ( "Apple consumed." ) ; available = false ; produced.signal ( ) ; //发信号唤醒等待这个Condition的线程 } finally { lock.unlock ( ) ; } } } // 测试用类 public class ConditionTester { public static void main( String [ ] args) throws InterruptedException { final Basket basket = new Basket( ) ; //定义一个producer Runnable producer = new Runnable ( ) { public void run( ) { try { basket.produce ( ) ; } catch ( InterruptedException ex) { ex.printStackTrace ( ) ; } } } ; //定义一个consumer Runnable consumer = new Runnable ( ) { public void run( ) { try { basket.consume ( ) ; } catch ( InterruptedException ex) { ex.printStackTrace ( ) ; } } } ; //各产生10个consumer和producer ExecutorService service = Executors.newCachedThreadPool ( ) ; for ( int i = 0 ; i < 10 ; i++ ) service.submit ( consumer) ; Thread .sleep ( 2000 ) ; for ( int i = 0 ; i < 10 ; i++ ) service.submit ( producer) ; service.shutdown ( ) ; } }
Condition配合Lock接口可以轻松实现,比sychronized配合wait,notify更
强大的功能.
Condition接口可以为单个对象锁生成多个类似wait-notify机制的条件变量.
每个条件变量在执行wait-notify时,只会控制自身条件的线程,即触发notify时,只唤醒
自身条件变量上的wait线程,不会唤醒其他条件变量的wait线程.
建议: 同一把锁下, 允许有多个Condition, 且相互不干涉, 但是, 每个Condition都是按顺序执行的.
(java关键字, 如果使用this, 则范围过大, 自己创建object来局部控制, 又不优雅)
注意: Condition的wait操作, 允许出现人为或意外的”虚假唤醒”, 所以, 为了保证Condition的作用域.
当调用wait时, 尝试使用循环结构.其中condition为await-singal的操作标示.
boolean condition = true ; while ( condition) { condition.await ( ) ; condition = false ; } ... condition = true ; condition.singal ( ) ;
6, 使用java.util.concurrent.atomic包,原子操作及解决volatile变量计算的race condition
private static AtomicInteger i = new AtomicInteger( 0 ) ; public void run( ) { int v = i.incrementAndGet ( ) ; // 相当于++i log.info ( "i = " + v) ; }
包的特色:
1, 普通原子数值类型AtomicInteger, AtomicLong提供一些原子操作的加减运算.
2, 解决race condition问题的经典模式-”比对后设定”, 即 查看主存中数据是否与
预期提供的值一致,如果一致,才更新.
// 这边采用无限循环 for ( ;; ) { int current = get( ) ; if ( compareAndSet( current, newValue) ) return current; }
3, 使用AtomicReference可以实现对所有对象的原子引用及赋值.包括Double与Float,
但不包括对其的计算.浮点的计算,只能依靠同步关键字或Lock接口来实现了.
4, 对数组元素里的对象,符合以上特点的, 也可采用原子操作.包里提供了一些数组原子操作类
建议: 针对非浮点类型的数值计算, 数组元素及对象的引用/赋值, 优先采用原子类型.
优先考虑使用atmoic框架 .
7, 利用java semaphore信号量机制,控制某操作上线程的数量
java信号量的实现逻辑与操作系统解决进程同步问题时采用的PV操作类似.
即 P -> 临界区 -> V
其中P为消费,V生产,临界区是同步区域.
java semaphore提供了acquire()与release()两种操作,类似Lock的lock()与unlock.
区别在于, java semaphore对acquire有数量控制,即利用它的计数器大小,来控制多少线程可执行,其余全部阻塞.
而Lock中的lock()方法,一次只能允许一根线程执行,其余全部阻塞.
semaphore接口的构造函数中还提供了 一个boolean型的fair变量,表示,是否公平.
如果为ture,则每个线程会根据到达的顺序执行,而默认是false.
// 业务逻辑实现类 public class Logic { private static final Log log = LogFactory.getLog ( Logic.class ) ; private AtomicInteger sum = new AtomicInteger( 0 ) ; private Semaphore sp = new Semaphore( 5 ) ; // 吞吐量为5条线程 public void test( ) { try { sp.acquire ( ) ; log.info ( Thread .currentThread ( ) .getName ( ) + " entered" ) ; Thread .sleep ( 2000 ) ; log.info ( sum.getAndIncrement ( ) ) ; sp.release ( ) ; } catch ( InterruptedException e) { log.error ( "sleep error:" , e) ; } } } // 线程测试类 public class RunThread { public static void main( String [ ] args) { final Logic logic = new Logic( ) ; //定义一个producer Runnable test = new Runnable ( ) { public void run( ) { logic.test ( ) ; } } ; ExecutorService service = Executors.newCachedThreadPool ( ) ; for ( int i = 0 ; i < 10 ; i++ ) { service.submit ( test) ; } service.shutdown ( ) ; } }
注意; semaphore可以控制某个资源上读取操作的线程数量, 但是, semaphore本身是线程不安全的,
如果资源涉及到写入操作, 那么在操作中加上同步后, 信号量的作用也就跟Lock接口一样了.(一次只能执行一根线程)
8, 利用CyclicBarrier屏障接口实现,线程集合/解散功能
java有好多种的屏障实现, 简单的几种如下:
a, 利用条件变量Condition实现wait-notify机制,等待所有的线程都wait在某一个
集合点时,notifyAll一下. 缺点是需要一根监控线程
b, 利用join方法,开一个监视线程, 每次调用这个线程取被block住的线程数量.
当达到指定数量后, 监视线程自动死亡,以放开所有的被block threads.
c, 利用CyclicBarrier提供的功能,只需要在集合点处调用await()方法,即可.
// 试验屏障功能的类 public class Logic { private static final Log log = LogFactory.getLog ( Logic.class ) ; private int value = 21 ; private CyclicBarrier cyclic = new CyclicBarrier( 3 ) ; public int getValue( ) { return value; } public void setValue( int value) { this .value = value; } public void expression1( ) { try { Thread .sleep ( 1000 ) ; log.info ( value/ 2 ) ; cyclic.await ( ) ; log.info ( Thread .currentThread ( ) .getName ( ) + " end." ) ; } catch ( InterruptedException e) { log.error ( e) ; } catch ( BrokenBarrierException e) { log.error ( e) ; } } public void expression2( ) { try { Thread .sleep ( 2000 ) ; log.info ( value* 2 ) ; cyclic.await ( ) ; log.info ( Thread .currentThread ( ) .getName ( ) + " end." ) ; } catch ( InterruptedException e) { log.error ( e) ; } catch ( BrokenBarrierException e) { log.error ( e) ; } } public void expression3( ) { try { Thread .sleep ( 3000 ) ; log.info ( value+ 2 ) ; cyclic.await ( ) ; log.info ( Thread .currentThread ( ) .getName ( ) + " end." ) ; } catch ( InterruptedException e) { log.error ( e) ; } catch ( BrokenBarrierException e) { log.error ( e) ; } } } // 线程测试类 public class RunThread { public static void main( String [ ] args) { final Logic logic = new Logic( ) ; Runnable run1 = new Runnable ( ) { public void run( ) { logic.expression1 ( ) ; } } ; Runnable run2 = new Runnable ( ) { public void run( ) { logic.expression2 ( ) ; } } ; Runnable run3 = new Runnable ( ) { public void run( ) { logic.expression3 ( ) ; } } ; //各产生10个consumer和producer ExecutorService service = Executors.newCachedThreadPool ( ) ; service.submit ( run1) ; service.submit ( run2) ; service.submit ( run3) ; service.shutdown ( ) ; } }
注意: 使用屏障的时候, 小心异常的放生,当发生异常,所有线程都会被释放
等待中的线程将被中断. 且发生异常的屏障将不可用,需要屏障的实例reset一下.
9, 利用CountDownLatch接口实现线程集合/解散功能,类似CyclicBarrier,区别是倒数且只跑一次
接口方法与CyclicBarrier基本相同,不同在于构造函数需要传入一数量,表示
倒数的开始数量.以后会递减这个值
发表评论
-
Raft
2018-07-12 14:20 734前言 上篇文章说解决问题要分而治之,先把分片的问题解决了再 ... -
java uuid
2017-09-14 18:18 555在java中产生uuid的方式是使用java.util.UU ... -
JAVA 编码规范
2017-09-06 11:34 406https://google.github.io/style ... -
mac 入门
2015-12-01 16:28 622http://foocoder.com/blog/wo-zai ... -
java 反编译工具gad
2014-05-09 12:04 963java 反编译工具gad,备个份。 -
java 代码大全(code book)
2014-04-29 10:59 1060参考这里: http://www.java2s.com/C ... -
SQL语法解析器JSQLParser
2014-02-09 19:53 2138SQL 语法解释器jsqlparser 是用java ... -
BufferedInputStream 深入研究。
2013-11-19 13:26 14181. BufferedInputStream的基本原理 ... -
java 启动脚本
2013-08-22 19:08 976java 启动脚本 #!/bin/bash cmd=&q ... -
CRLF escape
2013-08-06 17:51 1192最近需要对用户输入的CRLF即(\r\n)做escape, ... -
安全的自增类
2013-07-22 18:16 982java中一个计数器如果超过MAX_VALUE再自增会如何? ... -
solr日志被block的问题
2013-05-23 16:48 1255"catalina-exec-22386" ... -
beanMapper
2013-01-13 22:43 885实在被一堆get,set搞烦了,周末写了一个beanMappe ... -
java instanceof ,isInstance(),isAssignableFrom之前的差异
2013-01-06 11:00 958public class ItemQuery { ... -
通过gzip对字符串压缩
2012-12-22 18:10 3102通过GZIPOutputStream,GZIPInputStr ... -
关于URL编码
2012-12-21 14:18 1102一、问题的由来 URL就是网址,只要上网,就一定会用到。 ... -
spring的FactoryBean机制
2012-11-20 16:18 1221spring可以通过的FactoryBean的形式把一个Fac ... -
HashMap cpu占用 100%
2012-11-10 22:22 1805今天在重现出HashMap cpu占用100%了,只 ... -
文字扫描工具--java.util.Scanner
2012-11-10 14:33 1092A simple text scanner which c ... -
一个隐形的java int溢出
2012-11-06 22:17 1103故事的背景: 笔者最近在做一个类SNS的项目, ...
相关推荐
### Java多线程小结 #### 一、多线程的概念与意义 多线程是Java编程中的一个重要概念,指的是程序在运行时可以同时执行多个线程的能力。它能够提高程序的性能,尤其是在多核处理器的环境下。多线程使得程序能够更...
本文将对Java线程类进行深入的总结,并通过思维导图帮助理解各个类之间的关系。我们将探讨`Thread`类、`Runnable`接口、线程的状态、线程同步以及线程池等相关知识点。 1. **线程基础** - **Thread类**:Java中的`...
八、线程同步小结 Java线程:线程的交互 Java线程:线程的调度-休眠 Java线程:volatile关键字 Java线程:新特征-线程池 一、固定大小的线程池 二、单任务线程池 三、可变尺寸的线程池 四、延迟连接池 五、...
#### 五、小结 本文详细介绍了Java中线程的基本概念、创建方式、生命周期以及如何控制线程执行等知识点。通过实际示例代码展示了如何创建和使用线程,帮助读者更好地理解和应用Java线程技术。在实际开发中,合理...
### Java集合小结 #### 一、集合的概念与重要性 集合是Java编程语言中用于存储、管理和操作数据的一种重要工具。它提供了多种数据结构来适应不同的应用场景,从而有效地提高程序开发效率。从数据结构的角度来看,...
3.1 Java线程 3.2 创建线程 3.3 使用线程的缺点 3.3.1 初始启动变慢 3.3.2 资源利用 3.3.2 资源利用 3.4 线程管理 3.5 共享资源的使用同步 3.5.1 同步方法和同步代码块的嵌套调用...
#### 六、小结 本文从Java线程的基础入手,介绍了线程的两种创建方式——继承`Thread`类和实现`Runnable`接口,讨论了线程的基本操作,最后深入探讨了同步和死锁的概念。通过学习这些内容,读者可以更好地理解和...
1. **Java线程小结**:这部分内容可能涉及多线程编程的基础知识,如线程的创建、同步机制(synchronized、Lock等)、并发工具类(Semaphore、CountDownLatch、CyclicBarrier等),以及线程安全问题和解决方案。...
### Java个人学习小结 #### Java发展史及重要里程碑 - **起源与发展**: Java 的起源可以追溯到 1992 年,当时的 Sun Microsystems 公司开发了一种名为 Oak 的编程语言,最初是为了家用电器的智能化而设计的。然而...
《Java基础小结》 Java,作为一种广泛应用的编程语言,以其跨平台、面向对象的特点深受开发者喜爱。这篇博文和随附的PDF笔记旨在总结Java的基础知识,帮助初学者巩固理解,同时也为有经验的开发者提供回顾参考。 1...
#### 四、小结 Java多线程设计模式是Java并发编程的重要组成部分,能够有效地帮助开发者解决多线程环境下的各种问题,提高程序的性能和稳定性。理解并掌握这些模式对于编写高效、可靠的多线程应用程序至关重要。
这个“java课程小结.rar_北京理工大学JAVA课程”压缩包中包含的“课程小结”文件,很可能是教授精心编写的教学精华,旨在帮助学生巩固所学知识并为后续学习打下坚实基础。 在Java课程中,有几个核心概念和技术是必...
Java线程安全问题主要涉及到并发环境下多个线程对共享资源的访问和修改,这可能导致数据不一致、死锁等问题。Java内存模型(JMM)是Java语言为了保证跨平台的并发正确性而设定的一套规范,它规定了线程如何访问和...
### Java技巧小结荟萃 #### Javadoc API 文件产生器 Javadoc 是一款非常重要的工具,主要用于生成文档,能够从源代码注释中提取出有用的文档信息。这不仅有助于提高代码的可读性,还方便其他开发人员快速理解类、...
Java中的守护线程(Daemon Threads)是用于支持应用程序运行的重要组件,它们在后台执行任务,不会阻止Java虚拟机(JVM)的退出。守护线程的主要任务是为其他非守护线程提供服务,例如垃圾回收线程就是典型的守护...