先看一下下面的错误代码,对写加了synchronized控制,保证了写的安全,但是问题在哪里呢?
public class testTh7 { private String data; public String read(){ System.out.println(Thread.currentThread().getName() + "read data " + data); return this.data; } public synchronized void write(String data){ System.out.println(Thread.currentThread().getName() + " === write data " + data); this.data = data; } public static void main(String[] args) { final testTh7 t = new testTh7(); for (int i = 0; i < 100; i++) { if (i % 2 == 0) { new Thread(new Runnable() { @Override public void run() { Double d = Math.random(); t.write(d.toString()); } }).start(); } else { new Thread(new Runnable() { @Override public void run() { t.read(); } }).start(); } } } }
程序的前部分输出结果如下:
Thread-1read data null
Thread-0 === write data 0.8429852467390618
Thread-2 === write data 0.3111022600208211
Thread-3read data 0.3111022600208211
Thread-4 === write data 0.13391602356879362
Thread-5read data 0.13391602356879362
Thread-8 === write data 0.3014059888796128
Thread-6 === write data 0.7073336550466512
Thread-7read data 0.7073336550466512
Thread-9read data 0.7073336550466512
Thread-10 === write data 0.3157260014049781
Thread-11read data 0.3157260014049781
Thread-15read data 0.3157260014049781
Thread-14 === write data 0.9981422731405993
Thread-16 === write data 0.9011910270245219
Thread-12 === write data 0.34975057489898076
Thread-13read data 0.34975057489898076
Thread-17read data 0.34975057489898076
Thread-18 === write data 0.19089943846264656
Thread-19read data 0.19089943846264656
Thread-21read data 0.19089943846264656
Thread-20 === write data 0.38498810226852065
Thread-22 === write data 0.29234432278529343
Thread-23read data 0.29234432278529343
Thread-27read data 0.29234432278529343
Thread-24 === write data 0.28981062022967496
Thread-29read data 0.28981062022967496
Thread-28 === write data 0.1022791336198855
Thread-26 === write data 0.15466728987586276
Thread-25read data 0.15466728987586276
Thread-31read data 0.15466728987586276
Thread-32 === write data 0.13431233603464776
Thread-33read data 0.13431233603464776
Thread-35read data 0.13431233603464776
Thread-38 === write data 0.33289010029186195
Thread-37read data 0.13431233603464776
Thread-34 === write data 0.5545937895404677
Thread-30 === write data 0.9567137584265717
Thread-36 === write data 0.6461050880921616
可以看到Thread-37这行读取的数据已经不正确了,读取的上一次的旧数据,这不是线程安全的缓存设计。首先确认一下原则,只能有一个线程写操作,可以多个线程并发读,但是写时不能读,读时候不能写。
解决办法有多种,可以使用信号量,使用两个信号量,一个是读写的信号量,还有个是写的信号量,如果简单一点,也可以使用java已经封装的读写锁,代码如下,可以自己测试。
import java.util.concurrent.locks.ReentrantReadWriteLock; public class testReadWrite { private String data = null; private ReentrantReadWriteLock rw = new ReentrantReadWriteLock(); public void read() { rw.readLock().lock(); System.out.println(Thread.currentThread().getName() + " read data!"); System.out.println(Thread.currentThread().getName() + "read data " + data); rw.readLock().unlock(); } public void write(String data) { rw.writeLock().lock(); System.out.println(Thread.currentThread().getName() + " ===write data!"); this.data = data; System.out.println(Thread.currentThread().getName() + " ===write data: " + data); rw.writeLock().unlock(); } }
相关推荐
Java并发编程库,特别是java.util.concurrent(简称J.U.C),是Java语言在多线程处理上的一大亮点。并发编程是一个复杂的话题,因为它涉及到许多高级概念,包括线程安全、死锁、性能优化和原子操作等。J.U.C正是为了...
6. **多线程**:Java提供了强大的多线程支持。理解线程的创建、同步和通信,如synchronized关键字、wait()、notify()和notifyAll()方法,以及线程池的使用,对于编写高性能的并发程序至关重要。 7. **反射机制**:...
9. **多线程同步机制**:synchronized、volatile、java.util.concurrent包中的工具类等,都是Java并发编程的关键。了解它们的工作原理及误用后果是避免Bug的关键。 10. **编译器优化与陷阱**:Java的JIT编译器会在...
Java的高级特性也是PPT所不可或缺的内容,其中包括IO流的使用、多线程编程、网络编程等。这些高级特性将使学习者能够处理更复杂的编程任务,如文件的读写、数据传输、并发控制等。通过PPT中的图示和代码示例,学习者...
六、多线程 1. **线程概念**:理解并发和并行,以及线程的生命周期。 2. **线程创建**:通过Thread类和实现Runnable接口创建线程。 3. **线程同步**:学习synchronized关键字,死锁、活锁、饥饿问题,以及wait()、...
5. **多线程**:Thread类和Runnable接口用于实现并发执行,synchronized关键字和Lock接口用于线程同步,wait()、notify()、notifyAll()方法控制线程间通信。 6. **反射机制**:通过Class类和java.lang.reflect包下...
- 线程堆栈大小:适当减小-Xss值可以在相同的物理内存条件下创建更多的线程。 - 垃圾回收器选择:根据不同的应用场景选择合适的垃圾回收器,例如响应时间优先的并发收集器适用于对应用响应时间有较高要求的场景。 ...