线程的同步
来源:互联网 发布:json数据格式 编辑:程序博客网 时间:2024/06/02 03:24
线程的不确定性
由于cpu执行线程采取时间片轮询的方式,当某个操作还没执行完就调度到另一个线程。这就导致下次再调度到这个线程的时候。数据就会发生错乱。
举个例子:
我们创建两个相同线程,让他们对同一个数加1,每个加5次:
public class Main { private static int currentCount = 0; private static int NUM = 5; public static void main(String[] args) { new Thread(new MRunnable()).start(); new Thread(new MRunnable()).start(); } static class MRunnable implements Runnable { @Override public void run() { for (int i = 0; i < NUM; i++) { currentCount++; try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("最后结果:"+currentCount); } }}
当NUM为5的时候正常输出:
最后结果:10最后结果:10
当NUM为10的时候结果是这样的:
最后结果:18最后结果:18
运行多几次每次的结果都有可能不一样。
因为这种操作不是原子性的,在操作的过程中有可能没有存在内存里面,所以就导致的线程的不确定性。
多线程同步
由于同时运行的线程需要共享数据,就要考虑其他的线程的行为与状态,所以同步就产生了。
java利用对象的互斥性,来保证数据的完整。
- 每个对象对应一个互斥锁的标记,来保证线程访问对象的唯一性。
- 关键字synchronized
synchronized用法:
- 对代码块加锁
- 对某个方法加锁
用刚刚的例子,在直接对 for循环 上锁:
public class Main { private static int currentCount = 0; private static int NUM = 10; public static void main(String[] args) { new Thread(new MRunnable()).start(); new Thread(new MRunnable()).start(); } static class MRunnable implements Runnable { @Override public void run() { synchronized (this) { for (int i = 0; i < NUM; i++) { currentCount++; try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } System.out.println("最后结果:" + currentCount); } }}
经过运行了多次 结果都是:
最后结果:20最后结果:20
当for 循环拿到锁后,其他操作只能等待,当for循环执行完,释放锁后另一个线程才可以进去,这就保证了线程的安全性。
线程的同步控制
wait():当上锁的对象或方法需要等待其他操作的时候,就需要释放当前的锁,也就是等待其他的操作完成再来执行。
notify()或者notifyAll:让等待的方法进入就绪状态。
例子:
在一个数组中的get与add方法
static class MyArray { private int index = 0; private int[] array = new int[10]; public synchronized void put(int value) { //当数组元素为最大的时候,就需要等待get数据后再进行操作 while (array.length == index) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } array[index] = value; index++; this.notify(); } public synchronized int get() { //当数组元为0的时候,就需要等待add数据后再进行操作 while (index<= 0) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } index--; int val =array[index]; this.notify(); return val; } }
可以看出,当length=0的时候wait()等待释放锁,然后让put执行,通里put也一样。
死锁
死锁的情况有时很难查找出来,但有很重要,因为一旦死锁,程序就无法进行,一般死锁是两个锁之间互相等待对方执行导致的。网上也会有相应的例子
JDK从1.5以后就增加了更多的类,让使用锁机制更加灵活
比如:
- java.util.concurrent.locks包
- lock() 、tryLock()、unLock()
ReadWriteLock等接口
lock() 、tryLock()、unLock() 后面有时间在慢慢研究。
阅读全文
0 0
- 线程的同步-同步方法
- 线程的同步-同步块
- Java线程:线程的同步-同步方法
- Java线程:线程的同步-同步块
- Java线程:线程的同步-同步方法
- Java线程:线程的同步-同步块
- Java线程:线程的同步-同步方法
- Java线程:线程的同步-同步方法
- Java线程:线程的同步-同步块
- Java线程:线程的同步-同步方法
- Java线程:线程的同步-同步块
- Java线程:线程的同步-同步方法
- Java线程:线程的同步-同步块
- Java线程:线程的同步-同步方法
- Java线程:线程的同步-同步块
- Java线程:线程的同步-同步方法
- Java线程:线程的同步-同步块
- Java线程:线程的同步-同步方法
- PL/SQL学习笔记
- 提升Xcode编译性能--RAM磁盘编译,编译速速飞起来
- Maven項目的創建及SSM環境的搭建
- 多态部分作业 3..创建Rodent(啮齿动物):Mnouse(老鼠),Gerbil(鼹鼠),Hamster(大颊鼠)
- [面试]进程与线程的区别联系,并发和并行的区别
- 线程的同步
- git葵花宝典,GitLabWeb
- Oozie
- “自顶向下,逐步求精”的方法
- PostgreSQL时间加减
- 2017杭电新生赛 1001~1009
- 管道
- Log4J入门教程(一) 入门例程
- Qt ui控件代码先后顺序的tips