- 浏览: 2473389 次
- 性别:
- 来自: 杭州
文章分类
- 全部博客 (574)
- Book (62)
- Architecture (6)
- Java (39)
- Taobao (41)
- Distributed (4)
- Life (72)
- Database (7)
- Spring (16)
- Photography (15)
- Bicycle (41)
- Test (20)
- jBPM (8)
- Business (12)
- Movie (3)
- Ajax (15)
- Code (7)
- Eclipse (96)
- VIM (2)
- Music (6)
- Groovy (10)
- AutoHotKey (3)
- Dorado (10)
- Maven (7)
- Scrum (5)
- English (20)
- Financial (12)
- OSGi (3)
- Other (4)
- Tool (6)
- Browser (1)
- PPT (1)
- Project Management (4)
- Agile (6)
- Nosql (1)
- Search engine (6)
- Shell (2)
- Open Source (4)
- Storm (10)
- Guava (3)
- Baby (1)
- netty (1)
- Algorithm (1)
- Linux (1)
- Python (2)
最新评论
-
roy2011a:
https://github.com/ebottabi/sto ...
storm的序列化问题及与spring的结合方式 -
roy2011a:
能抗能打 写道哥们儿,你好!能共享下那个storm与sprin ...
storm的序列化问题及与spring的结合方式 -
Alick1:
兄弟,你之前是不是在深圳的正阳公司呆过啊?
storm的ack和fail -
liuleixwd:
先点个赞,写的非常好!有个问题请教下,如果我再bolt里不用e ...
storm的ack和fail -
yao-dd:
solr的facet查询
引子
一点体会:对并发和多线程的学习理解, 最好多作几个例子跟踪调试实战一把, 可能会理解的更深刻些. 比如像我这样
Java内存模型
共享数据保存在主存储器中, 计算机将数据中主存储器读到寄存器中, 然后进行操作, 一般情况下, 对寄存器的操作速度要比主存储器要快.
Lock(锁机制)
...
synchronized
当线程进入synchronized方法或者代码块的时候, 它必须重新将数据从主存储器中加载到当前线程的寄存器中.并对同步的对象加锁,从而阻塞其他线程的进入, 线程在离开之前再将寄存器中的数据同步到主存储器中并释放锁.
synchronized只会对共享的内容有效, 如果不存在同时对共享内容进行操作, 则同步毫无意义.比如下面的测试代码:
这里虽然使用到了synchronized块, 但是该方法不存在对公共的内容进行加锁, 而锁住的是两个不同的domain, 如果锁定的对象改成this则就回达到我们期望的结果
synchronized修饰的方法和代码块, 一次只能有一个线程访问, 而一个类的多个方法被synchronized修饰, 则这些方法只能由一个线程访问, 但是这里有一个区别, 静态synchronized方法之间只允许一个线程访问, 非静态的synchronized方法之间只允许一个线程访问, 静态和非静态方法之间不存在互斥的情况.比如:
这两个方法之间不会互为阻塞.
在可能的情况下,一般尽量将要同步的代码最小化, 这样可以达到线程的阻塞最小化.
对于下面两个同步方法:
如果线程a执行到method1()方法, 而线程b同时执行到method2()方法则会被阻塞, 直到线程a退出method1()方法为止.
而对于下面的测试则是另外一种情况:
这主要是因为如果synchronized块中是domain的话, 那么synchronized方法锁住的是this对象, synchronized锁住的是domain对象, 因此两个synchronized互不影响.
volatile
volatile是一种轻量级的synchronized, synchronized是对代码块和方法加锁进行同步, 而volatile修饰的共享变量能保证在多线程状态下做到同步, 通常情况下多线程在操作共享变量的时候, 都会在工作内存中将主存中的共享变量复制一份, 因此在一个线程中修改了共享变量, 可能还没有更新到主存中, 而另一个线程又访问了主存中的共享变量, 这样将导致另一个线程使用过期的数据, 使用volatile修饰的共享变量则能保证线程操作的都是主存中的共享变量, 工作变量不会在工作内存拷贝一份再处理, 这样就保证了多个线程访问到的共享变量时刻都是最新的, 因为都在主存中操作volatile共享变量, 因此保证对共享变量的修改是"原子"级的操作(不存在工作内存和主存之间的同步更新), 因此实现了线程安全. 比如说有一个共享变量i, 然后在一个方法中有这样的操作i++, 它实际上是一个包含了三个操作的复合操作:读, 改, 写. 如果不对i不加volatile, i又在另外一个线程中被修改, 那么可能出现i++操作读的时候是另外一个线程未更新前的值, 改的同时另一个线程的工作内存中的变量与主存在做同步更新, 最后写的时候就会将另外一个线程的修改覆盖掉. 从上面的例子中可以看出, 这种情况需要较高的压力与并发情况下, 才会出现. 同时这个例子即使使用volatile也无法完全保证线程安全, 必须将i++操作使用synchronized包装成一个原子操作, 或者使用jdk1.5的atomic原子包中的类实现原子操作.
volatile 变量仅能被安全地用在单一的载入或存储操作。这个限制导致volatile变量的使用是不常见的。
理论上每一个线程都有自己的寄存器来存放操作数据. 而使用volatile, 则可以保存每个线程操作的数据保存在主存储器中, 达到多个线程之间能够共享
原子变量(AtomicLong, AtomicInteger, AtomicReference)
J2SE 5.0提供了一组atomic class来帮助我们简化同步处理。基本工作原理是使用了同步synchronized的方法实现了对一个long, integer, 对象的增、减、赋值(更新)操作. 比如对于++运算符AtomicInteger可以将它持有的integer 能够atomic 地递增。在需要访问两个或两个以上 atomic变量的程序代码(或者是对单一的atomic变量执行两个或两个以上的操作)通常都需要被synchronize以便两者的操作能够被当作是一个atomic的单元。
对array atomic变量来说,一次只有一个索引变量可以变动,并没有功能可以对整个array做atomic化的变动。
关于Atomic的几个方法
getAndSet() : 设置新值,返回旧值.
compareAndSet(expectedValue, newValue) : 如果当前值(current value)等于期待的值(expectedValue), 则原子地更新指定值为新值(newValue), 如果更新成功,返回true, 否则返回false, 换句话可以这样说: 将原子变量设置为新的值, 但是如果从我上次看到的这个变量之后到现在被其他线程修改了(和我期望看到的值不符), 那么更新失败
从effective java (2)中拿来的一个关于AtomicReference的一个例子:
上面的例子比较容易懂, 不过貌似没什么价值, 而在实际的应用中, 我们一般采用下面的方式来使用atomic class:
类似i++这样的"读-改-写"复合操作(在一个操作序列中, 后一个操作依赖前一次操作的结果), 在多线程并发处理的时候会出现问题, 因为可能一个线程修改了变量, 而另一个线程没有察觉到这样变化, 当使用原子变量之后, 则将一系列的复合操作合并为一个原子操作,从而避免这种问题, i++=>i.incrementAndGet()
原子变量只能保证对一个变量的操作是原子的, 如果有多个原子变量之间存在依赖的复合操作, 也不可能是安全的, 另外一种情况是要将更多的复合操作作为一个原子操作, 则需要使用synchronized将要作为原子操作的语句包围起来. 因为涉及到可变的共享变量(类实例成员变量)才会涉及到同步, 否则不必使用synchronized
wait, notify, notifyAll, sleep, yield
wait暂停被当前同步锁当前线程的执行, 同时线程会释放其同步锁, 使用同一锁的线程将有机会通过notify或notifyAll被唤醒
notify唤醒当前暂停的线程进入执行队列等待执行
notifyAll会唤醒多个线程进入执行队列, 这些线程根据最终的竞争结果被继续执行
sleep暂停当前线程的执行, 但是不释放同步锁, 这样使用同一锁的线程将被阻塞
yield会将当前线程暂时让位一小段时间,让其它的线程有机会运行,过了这段时间后,该线程继承运行。上述功能也可以用Thread.sleep()方法实现。简单的说就是在线程执行过程中sleep(0)一下, 让其他等待的线程继续运行
线程安全
编写线程安全的代码,本质上就是管理对状态(state)的访问,而且通常都是共享的、可变的状态。这里的状态就是对象的变量(静态变量和实例变量)
线程安全的前提是该变量是否被多个线程访问, 保证对象的线程安全性需要使用同步来协调对其可变状态的访问;若是做不到这一点,就会导致脏数据和其他不可预期的后果。无论何时,只要有多于一个的线程访问给定的状态变量,而且其中某个线程会写入该变量,此时必须使用同步来协调线程对该变量的访问。Java中首要的同步机制是synchronized关键字,它提供了独占锁。除此之外,术语“同步”还包括volatile变量,显示锁和原子变量的使用。
在没有正确同步的情况下,如果多个线程访问了同一个变量,你的程序就存在隐患。有3种方法修复它:
l 不要跨线程共享变量;
l 使状态变量为不可变的;或者
l 在任何访问状态变量的时候使用同步。
当多个线程访问一个类时,如果不用考虑这些线程在运行时环境下的调度和交替执行,并且不需要额外的同步及在调用方代码不必作其他的协调,这个类的行为仍然是正确的,那么称这个类是线程安全的。
如果共享变量在多个方法中访问到, 当在多线程环境下, 仅仅对其中一个方法使用synchronized是不够的, 为了保证线程安全, 必须对多个方法都使用synchronized, 具体做法可以参看vector, vector相对于list来说, 是线程安全的, 它的所有公共的方法都是synchronized, 这也是synchronized的另一个作用, 保证所有方法使用的共享变量不是过期数据.
util.concurrent
map的数据结构, map内部是一个存放单向链接的Entry元素的一维数组(map称之为bucket), 首先根据每一个元素的key的hashcode按照一维数组的length取模, 得到的结果就是该元素存放在这个数组的位置, 存放在这个数组的元素可能有多个, 这些元素将通过单向链表的方式进行关联
HashTable是线程安全的, 因此它的所有方法都是synchronized的, 而HashMap是非线程安全的. 但是传统的HashTable在高性能的环境下性能很差, 因为每次只能有一个线程对HashTable进行读写, 而针对大量读, 少量写的应用场景来说, 只能一个线程能读将严重影响性能, 为了解决这个问题, 将原来对整个Map锁定改成对Map中的一个或几个bucket锁定(即减小锁的粒度)来实现能有多个线程能同时进行读,写操作. 对于大量的读操作(get), 少量的写操作(set), concurrent采用了copy-on-write策略, 即对于写操作, 将后台的数组复制一份, 然后对副本进行写操作, 完成之后, 替换原来的数组, 这样可以不影响读操作. 其实现有CopyOnWriteArrayList和CopyOnWriteArraySet
线程池是为发挥多线程的优点(并发),避免多线程的缺点(创建和销毁的时空开销)而出现的. 一个比较简单的线程池至少应包含线程池管理器、工作线程、任务队列、任务接口等部分。其中线程池管理器(ThreadPool Manager)的作用是创建、销毁并管理线程池,将工作线程放入线程池中;工作线程是一个可以循环执行任务的线程,在没有任务时进行等待;任务队列的作 用是提供一种缓冲机制,将没有处理的任务放在任务队列中;任务接口是每个任务必须实现的接口,主要用来规定任务的入口、任务执行完后的收尾工作、任务的执 行状态等,工作线程通过该接口调度任务的执行。
一点体会:对并发和多线程的学习理解, 最好多作几个例子跟踪调试实战一把, 可能会理解的更深刻些. 比如像我这样
Java内存模型
共享数据保存在主存储器中, 计算机将数据中主存储器读到寄存器中, 然后进行操作, 一般情况下, 对寄存器的操作速度要比主存储器要快.
Lock(锁机制)
...
synchronized
当线程进入synchronized方法或者代码块的时候, 它必须重新将数据从主存储器中加载到当前线程的寄存器中.并对同步的对象加锁,从而阻塞其他线程的进入, 线程在离开之前再将寄存器中的数据同步到主存储器中并释放锁.
synchronized只会对共享的内容有效, 如果不存在同时对共享内容进行操作, 则同步毫无意义.比如下面的测试代码:
public class SyncTest { public void syncMethod1(SyncDomain domain) { synchronized (domain) { System.out.println(domain.getStr()); } } public static void main(String[] args) { final SyncTest test = new SyncTest(); new Thread() { @Override public void run() { SyncDomain domain = new SyncDomain(); domain.setStr("t1"); test.syncMethod1(domain); } }.start(); new Thread() { @Override public void run() { SyncDomain domain = new SyncDomain(); domain.setStr("t2"); test.syncMethod1(domain); } }.start(); }
这里虽然使用到了synchronized块, 但是该方法不存在对公共的内容进行加锁, 而锁住的是两个不同的domain, 如果锁定的对象改成this则就回达到我们期望的结果
synchronized修饰的方法和代码块, 一次只能有一个线程访问, 而一个类的多个方法被synchronized修饰, 则这些方法只能由一个线程访问, 但是这里有一个区别, 静态synchronized方法之间只允许一个线程访问, 非静态的synchronized方法之间只允许一个线程访问, 静态和非静态方法之间不存在互斥的情况.比如:
public synchronized static void method1(){...} public synchronized void method2(){...}
这两个方法之间不会互为阻塞.
在可能的情况下,一般尽量将要同步的代码最小化, 这样可以达到线程的阻塞最小化.
对于下面两个同步方法:
public synchronized void method1(){...} public synchronized void method2(){...}
如果线程a执行到method1()方法, 而线程b同时执行到method2()方法则会被阻塞, 直到线程a退出method1()方法为止.
而对于下面的测试则是另外一种情况:
public class SyncBlockAndNonBlockMethodTest { public synchronized void syncMethod1(SyncDomain domain) { System.out.println(domain.getStr() + ": invoke before"); } public void syncMethod2(SyncDomain domain) { // 如果同步块锁定的是this, 那么执行syncMethod2方法时, 访问syncMethod1方法的线程将被阻塞 // 而如果同步块锁定的是domain, 那么两个同步方法互不影响 synchronized(domain) { System.out.println(domain.getStr() + ": invoke before"); } } public static void main(String[] args) { final SyncBlockAndNonBlockMethodTest test = new SyncBlockAndNonBlockMethodTest(); final SyncDomain domain = new SyncDomain(); new Thread() { @Override public void run() { // 断点1 domain.setStr("t1"); test.syncMethod1(domain); } }.start(); new Thread() { @Override public void run() { //SyncDomain domain = new SyncDomain(); // 断点2 domain.setStr("t2"); test.syncMethod2(domain); } }.start(); } }
这主要是因为如果synchronized块中是domain的话, 那么synchronized方法锁住的是this对象, synchronized锁住的是domain对象, 因此两个synchronized互不影响.
volatile
volatile是一种轻量级的synchronized, synchronized是对代码块和方法加锁进行同步, 而volatile修饰的共享变量能保证在多线程状态下做到同步, 通常情况下多线程在操作共享变量的时候, 都会在工作内存中将主存中的共享变量复制一份, 因此在一个线程中修改了共享变量, 可能还没有更新到主存中, 而另一个线程又访问了主存中的共享变量, 这样将导致另一个线程使用过期的数据, 使用volatile修饰的共享变量则能保证线程操作的都是主存中的共享变量, 工作变量不会在工作内存拷贝一份再处理, 这样就保证了多个线程访问到的共享变量时刻都是最新的, 因为都在主存中操作volatile共享变量, 因此保证对共享变量的修改是"原子"级的操作(不存在工作内存和主存之间的同步更新), 因此实现了线程安全. 比如说有一个共享变量i, 然后在一个方法中有这样的操作i++, 它实际上是一个包含了三个操作的复合操作:读, 改, 写. 如果不对i不加volatile, i又在另外一个线程中被修改, 那么可能出现i++操作读的时候是另外一个线程未更新前的值, 改的同时另一个线程的工作内存中的变量与主存在做同步更新, 最后写的时候就会将另外一个线程的修改覆盖掉. 从上面的例子中可以看出, 这种情况需要较高的压力与并发情况下, 才会出现. 同时这个例子即使使用volatile也无法完全保证线程安全, 必须将i++操作使用synchronized包装成一个原子操作, 或者使用jdk1.5的atomic原子包中的类实现原子操作.
volatile 变量仅能被安全地用在单一的载入或存储操作。这个限制导致volatile变量的使用是不常见的。
理论上每一个线程都有自己的寄存器来存放操作数据. 而使用volatile, 则可以保存每个线程操作的数据保存在主存储器中, 达到多个线程之间能够共享
原子变量(AtomicLong, AtomicInteger, AtomicReference)
J2SE 5.0提供了一组atomic class来帮助我们简化同步处理。基本工作原理是使用了同步synchronized的方法实现了对一个long, integer, 对象的增、减、赋值(更新)操作. 比如对于++运算符AtomicInteger可以将它持有的integer 能够atomic 地递增。在需要访问两个或两个以上 atomic变量的程序代码(或者是对单一的atomic变量执行两个或两个以上的操作)通常都需要被synchronize以便两者的操作能够被当作是一个atomic的单元。
对array atomic变量来说,一次只有一个索引变量可以变动,并没有功能可以对整个array做atomic化的变动。
关于Atomic的几个方法
getAndSet() : 设置新值,返回旧值.
compareAndSet(expectedValue, newValue) : 如果当前值(current value)等于期待的值(expectedValue), 则原子地更新指定值为新值(newValue), 如果更新成功,返回true, 否则返回false, 换句话可以这样说: 将原子变量设置为新的值, 但是如果从我上次看到的这个变量之后到现在被其他线程修改了(和我期望看到的值不符), 那么更新失败
从effective java (2)中拿来的一个关于AtomicReference的一个例子:
public class AtomicTest { private int x, y; private enum State { NEW, INITIALIZING, INITIALIZED }; private final AtomicReference<State> init = new AtomicReference<State>(State.NEW); public AtomicTest() { } public AtomicTest(int x, int y) { initialize(x, y); } private void initialize(int x, int y) { if (!init.compareAndSet(State.NEW, State.INITIALIZING)) { throw new IllegalStateException("initialize is error"); } this.x = x; this.y = y; init.set(State.INITIALIZED); } public int getX() { checkInit(); return x; } public int getY() { checkInit(); return y; } private void checkInit() { if (init.get() == State.INITIALIZED) { throw new IllegalStateException("uninitialized"); } } }
上面的例子比较容易懂, 不过貌似没什么价值, 而在实际的应用中, 我们一般采用下面的方式来使用atomic class:
public class CounterTest { AtomicInteger counter = new AtomicInteger(0); public int count() { int result; boolean flag; do { result = counter.get(); // 断点 // 单线程下, compareAndSet返回永远为true, // 多线程下, 在与result进行compare时, counter可能被其他线程set了新值, 这时需要重新再取一遍再比较, // 如果还是没有拿到最新的值, 则一直循环下去, 直到拿到最新的那个值 flag = counter.compareAndSet(result, result + 1); } while (!flag); return result; } public static void main(String[] args) { final CounterTest c = new CounterTest(); new Thread() { @Override public void run() { c.count(); } }.start(); new Thread() { @Override public void run() { c.count(); } }.start(); new Thread() { @Override public void run() { c.count(); } }.start(); } }
类似i++这样的"读-改-写"复合操作(在一个操作序列中, 后一个操作依赖前一次操作的结果), 在多线程并发处理的时候会出现问题, 因为可能一个线程修改了变量, 而另一个线程没有察觉到这样变化, 当使用原子变量之后, 则将一系列的复合操作合并为一个原子操作,从而避免这种问题, i++=>i.incrementAndGet()
原子变量只能保证对一个变量的操作是原子的, 如果有多个原子变量之间存在依赖的复合操作, 也不可能是安全的, 另外一种情况是要将更多的复合操作作为一个原子操作, 则需要使用synchronized将要作为原子操作的语句包围起来. 因为涉及到可变的共享变量(类实例成员变量)才会涉及到同步, 否则不必使用synchronized
wait, notify, notifyAll, sleep, yield
wait暂停被当前同步锁当前线程的执行, 同时线程会释放其同步锁, 使用同一锁的线程将有机会通过notify或notifyAll被唤醒
notify唤醒当前暂停的线程进入执行队列等待执行
notifyAll会唤醒多个线程进入执行队列, 这些线程根据最终的竞争结果被继续执行
sleep暂停当前线程的执行, 但是不释放同步锁, 这样使用同一锁的线程将被阻塞
yield会将当前线程暂时让位一小段时间,让其它的线程有机会运行,过了这段时间后,该线程继承运行。上述功能也可以用Thread.sleep()方法实现。简单的说就是在线程执行过程中sleep(0)一下, 让其他等待的线程继续运行
线程安全
编写线程安全的代码,本质上就是管理对状态(state)的访问,而且通常都是共享的、可变的状态。这里的状态就是对象的变量(静态变量和实例变量)
线程安全的前提是该变量是否被多个线程访问, 保证对象的线程安全性需要使用同步来协调对其可变状态的访问;若是做不到这一点,就会导致脏数据和其他不可预期的后果。无论何时,只要有多于一个的线程访问给定的状态变量,而且其中某个线程会写入该变量,此时必须使用同步来协调线程对该变量的访问。Java中首要的同步机制是synchronized关键字,它提供了独占锁。除此之外,术语“同步”还包括volatile变量,显示锁和原子变量的使用。
在没有正确同步的情况下,如果多个线程访问了同一个变量,你的程序就存在隐患。有3种方法修复它:
l 不要跨线程共享变量;
l 使状态变量为不可变的;或者
l 在任何访问状态变量的时候使用同步。
当多个线程访问一个类时,如果不用考虑这些线程在运行时环境下的调度和交替执行,并且不需要额外的同步及在调用方代码不必作其他的协调,这个类的行为仍然是正确的,那么称这个类是线程安全的。
如果共享变量在多个方法中访问到, 当在多线程环境下, 仅仅对其中一个方法使用synchronized是不够的, 为了保证线程安全, 必须对多个方法都使用synchronized, 具体做法可以参看vector, vector相对于list来说, 是线程安全的, 它的所有公共的方法都是synchronized, 这也是synchronized的另一个作用, 保证所有方法使用的共享变量不是过期数据.
util.concurrent
map的数据结构, map内部是一个存放单向链接的Entry元素的一维数组(map称之为bucket), 首先根据每一个元素的key的hashcode按照一维数组的length取模, 得到的结果就是该元素存放在这个数组的位置, 存放在这个数组的元素可能有多个, 这些元素将通过单向链表的方式进行关联
HashTable是线程安全的, 因此它的所有方法都是synchronized的, 而HashMap是非线程安全的. 但是传统的HashTable在高性能的环境下性能很差, 因为每次只能有一个线程对HashTable进行读写, 而针对大量读, 少量写的应用场景来说, 只能一个线程能读将严重影响性能, 为了解决这个问题, 将原来对整个Map锁定改成对Map中的一个或几个bucket锁定(即减小锁的粒度)来实现能有多个线程能同时进行读,写操作. 对于大量的读操作(get), 少量的写操作(set), concurrent采用了copy-on-write策略, 即对于写操作, 将后台的数组复制一份, 然后对副本进行写操作, 完成之后, 替换原来的数组, 这样可以不影响读操作. 其实现有CopyOnWriteArrayList和CopyOnWriteArraySet
线程池是为发挥多线程的优点(并发),避免多线程的缺点(创建和销毁的时空开销)而出现的. 一个比较简单的线程池至少应包含线程池管理器、工作线程、任务队列、任务接口等部分。其中线程池管理器(ThreadPool Manager)的作用是创建、销毁并管理线程池,将工作线程放入线程池中;工作线程是一个可以循环执行任务的线程,在没有任务时进行等待;任务队列的作 用是提供一种缓冲机制,将没有处理的任务放在任务队列中;任务接口是每个任务必须实现的接口,主要用来规定任务的入口、任务执行完后的收尾工作、任务的执 行状态等,工作线程通过该接口调度任务的执行。
发表评论
-
使用Externalization更高效的实现java对象序列化
2012-04-04 22:38 3152Externalization没用过, 它通过牺牲默认序列化的 ... -
关于java的检查异常和非检查异常
2012-04-04 21:31 4980这里有一个关于java的检查异常和非检查异常的观点, 我比较赞 ... -
使用ThreadLocal保证DateFormat线程安全
2012-04-03 06:45 3606大家都知道DateFormat是线程非安全的, 一般在多线程环 ... -
使用枚举实现一个状态机
2012-04-02 23:14 3945非常巧妙的一个使用枚举的例子.原文见这里 interface ... -
一个同步队列例子
2012-04-02 21:35 1578这个用的也比较少, 做一个参考, 原文见这里 private ... -
一个读写锁的例子
2012-04-02 21:20 1534用的比较少, 做一个参考. 原文在这里 public clas ... -
如何计算一个合适的线程池大小参数
2012-04-02 20:57 9072原文在这里 下面是一个计算的框架代码: /** * A ... -
正确使用日志的10个技巧
2012-02-11 21:13 28861做一个苦逼的Java攻城师, 我们除了关心系统的架构这种hig ... -
Java编程最差实践
2012-02-04 17:54 26671原文地址:http://www.odi.ch/prog/des ... -
利用jOOR简化Java 反射使用
2012-01-15 20:39 5159原文:http://lukaseder.wordpress.c ... -
《Java Performance》书评
2012-01-15 18:32 2967原文: http://java.dzone.com/rev ... -
《细说Java》读书笔记
2011-10-05 15:01 1998国人写的, 感觉是一 ... -
《Java开发超级工具集》读书笔记
2011-09-28 08:59 2102"工欲善其事必先利其器", 在平时的开发 ... -
《effective java》 读书笔记
2011-07-02 14:52 7608读第一版已经是好几年前的事儿了, 现在想起来也没什么印象, ... -
用java实现"awk -d"功能(保留多行重复)
2010-06-07 21:48 3078一般用过linux脚本的都知道"awk -d&quo ... -
关于方法返回值的两种处理模式
2010-05-13 09:06 2035目前在处理返回值方面, ... -
JVM调优汇总
2010-02-21 19:18 14419参考网址 http://pengjiaheng.spaces. ... -
log4j的输出转换模式
2009-12-12 10:02 1280转换模式(conversion pattern)为" ... -
java正则表达式用法举例
2009-12-08 11:27 4523java正则表达式真难用啊, 这里整理一个java正则表达式用 ... -
Ibatis TypeHandler使用总结
2009-11-25 19:33 16554ibatis中有一个TypeHandler(准确的说应该是Ty ...
相关推荐
总之,Java的多线程和并发编程是一个复杂而重要的主题,它涉及到操作系统原理、JVM行为、线程管理、同步机制等多个方面,熟练掌握这些知识对于开发高效、可靠的Java应用程序至关重要。通过理解线程的工作原理和使用...
Netty多线程并发编程知识点总结 Netty多线程并发编程是指在Netty框架中使用多线程技术来实现高性能、高并发的网络编程。下面是关于Netty多线程并发编程的知识点总结: 一、 JAVA 内存模型与多线程编程 在Java中,...
Java多线程与并发编程是Java...总之,Java多线程与并发编程是Java程序员必须掌握的核心技能,它涉及到操作系统原理、JVM内部机制以及Java提供的各种并发工具,熟练掌握这些知识对于编写高效、稳定的并发程序至关重要。
│ 高并发编程第二阶段04讲、多线程的休息室WaitSet详细介绍与知识点总结.mp4 │ 高并发编程第二阶段05讲、一个解释volatile关键字作用最好的例子.mp4 │ 高并发编程第二阶段06讲、Java内存模型以及CPU缓存不一致...
Java多线程与并发编程是Java开发中不可或缺的一部分,它涉及到操作系统的基础概念、JVM的工作原理以及Java语言特性。多线程允许程序同时执行多个任务,以充分利用CPU资源,提高系统的效率和响应性。 首先,理解多...
一种典型的多线程并发服务器架构如下: - **主监听线程**:负责接收客户端连接请求。 - **工作线程池**:由多个工作线程组成,负责处理具体的客户端请求。 **3. 示例代码片段** 下面是一个简单的多线程服务器示例...
Java多线程编程是Java语言的核心特性之一,...这些知识点是Java多线程编程的精髓,涵盖了从创建线程到线程间协作、线程安全与死锁处理等多个方面。掌握这些知识点对于编写高效、稳定、可维护的Java多线程程序至关重要。
本文主要围绕Linux下C语言实现的多线程编程进行知识点总结,涉及线程与进程的区别、多线程的优势、Pthreads API以及线程安全和死锁预防。 首先,线程和进程是操作系统中两种基本的执行单元。线程是进程内部的执行流...
这份“JAVA多线程编程技术PDF”是学习和掌握这一领域的经典资料,涵盖了多线程的全部知识点。 首先,多线程的核心概念包括线程的创建与启动。在Java中,可以通过实现Runnable接口或继承Thread类来创建线程。创建后...
Python多进程并发与多...以上知识点总结了Python在多进程并发和多线程并发编程方面的概念、优势与劣势、实现方法、注意事项等内容。掌握了这些知识点,可以帮助开发人员在实际应用中设计出更加高效和稳定的并发程序。
以下是对Java多线程、并发编程的一些关键知识点的详细阐述: 1. **线程创建**: - 接口方式:通过实现`Runnable`接口,然后通过`Thread`类构造器传入`Runnable`实例来创建线程。 - 类方式:直接继承`Thread`类并...
│ 高并发编程第二阶段04讲、多线程的休息室WaitSet详细介绍与知识点总结.mp4 │ 高并发编程第二阶段05讲、一个解释volatile关键字作用最好的例子.mp4 │ 高并发编程第二阶段06讲、Java内存模型以及CPU缓存不一致...
在IT领域,多线程并发服务器是网络编程中的一个重要概念,尤其在高并发场景下,如网站、在线游戏和实时数据处理系统等。这个毕业设计的主题是“多线程并发服务器”,采用C++语言实现,这表明我们将在讨论中涵盖C++...
Java多线程与并发编程是软件开发中的重要领域,它涉及到如何高效地利用计算机资源,尤其是CPU,使得多个任务能够同时或并发地执行。在Java中,多线程的运用可以提升程序的响应速度和执行效率,特别是在处理大量并发...
Java多线程是Java编程语言中一个非常重要的概念...理解这些知识点对于解决并发编程中的问题,比如资源竞争、死锁、线程安全性等问题,至关重要。在实际开发中,正确地应用多线程机制可以显著提升程序的性能和用户体验。
《Java并发编程实践》是一本深入探讨Java多线程编程的权威著作,它详细阐述了在并发环境下如何设计和实现高效、可靠的程序。这本书涵盖了Java并发编程的核心概念、工具和最佳实践,对于想要提升Java并发编程技能的...
### Linux多线程 C语言编程知识点总结 #### 一、多线程与多进程编程概述 **多线程**的概念可以追溯到20世纪60年代,然而直到80年代中期,这一机制才被正式引入到Unix系统中。随着计算机硬件的发展及软件需求的增加...
本书是关于多线程编程的权威指南,它涵盖了编写高效、安全的多线程程序所需的所有重要知识点。 描述中提到,这是一本“经典多线程文档”,表明了其在行业内的地位和影响力。书中描述了多线程之间的交互和通信机制,...