一、volatile介绍
volatile是一个类型修饰符(type specifier),就像大家更熟悉的const一样,它是被设计用来修饰被不同线程访问和修改的变量。volatile的作用是作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。
volatile作用:
简单地说就是防止编译器对代码进行优化。比如如下程序:
4XBYTE[2]=0x55;
XBYTE[2]=0x56;
XBYTE[2]=0x57;
XBYTE[2]=0x58;
对外部硬件而言,上述四条语句分别表示不同的操作,会产生四种不同的动作,但是编译器却会对上述四条语句进行优化,认为只有XBYTE[2]=0x58(即忽略前三条语句,只产生一条机器代码)。如果键入volatile,则编译器会逐一地进行编译并产生相应的机器代码(产生四条代码)。
正确使用volatile变量的条件:
只能在有限的一些情形下使用 volatile变量替代锁。要使 volatile变量提供理想的线程安全,必须同时满足下面两个条件:
● 对变量的写操作不依赖于当前值。
● 该变量没有包含在具有其他变量的不变式中。
实际上,这些条件表明,可以被写入 volatile变量的这些有效值独立于任何程序的状态,包括变量的当前状态。
第一个条件的限制使 volatile变量不能用作线程安全计数器。虽然增量操作(x++)看上去类似一个单独操作,实际上它是一个由读取-修改-写入操作序列组成的组合操作,必须以原子方式执行,而 volatile 不能提供必须的原子特性。实现正确的操作需要使 x 的值在操作期间保持不变,而 volatile变量无法实现这点。(然而,如果将值调整为只从单个线程写入,那么可以忽略第一个条件。)
大多数编程情形都会与这两个条件的其中之一冲突,使得 volatile变量不能像 synchronized 那样普遍适用于实现线程安全。清单 1 显示了一个非线程安全的数值范围类。它包含了一个不变式 —— 下界总是小于或等于上界。
二、多线程的介绍
多线程(英语:multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。具有这种能力的系统包括对称多处理机、多核心处理器以及芯片级多处理(Chip-level multithreading)或同时多线程(Simultaneous multithreading)处理器。[1] 在一个程序中,这些独立运行的程序片段叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理(Multithreading)”。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程(***译作“执行绪”),进而提升整体处理性能。
多线程用途:
用途在大多数研究领域内是要求线程调度程序要能够快速选择其中一个已就绪线程去运行,而不是一个一个运行而降低效率。所以要让调度程序去分辨线程的优先级是很重要的。而线程调度程序可能是以硬件、软件,或是软硬件并存的形式存在。
多线程的优点:
使用线程可以把占据时间长的程序中的任务放到后台去处理
用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度·
程序的运行速度可能加快
在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下可以释放一些珍贵的资源如内存占用等等
多线程技术在IOS软件开发中也有举足轻重的位置
多线程的缺点:
如果有大量的线程,会影响性能,因为操作系统需要在它们之间切换。
更多的线程需要更多的内存空间。
线程可能会给程序带来更多“bug”,因此要小心使用。
线程的中止需要考虑其对程序运行的影响。
通常块模型数据是在多个线程间共享的,需要防止线程死锁情况的发生。
三、多线程中volatile使用的理解
package com.casking.cdds.modules.test.web;
public class Counter {
//volatile关键字能保证多个内存块中的引用值是最新的可见性,不能保证原子性。可见性只能保证每次读取的是最新的值,但是volatile没办法保证对变量的操作的原子性。
public volatile static int count = 0;
public synchronized static void inc() {
// 这里延迟1秒,使得结果明显
try {
Thread.sleep(1);
} catch (InterruptedException e) {
}
count++;
}
public static void main(String[] args) {
// 同时启动1000个线程,去进行i++计算,看看实际结果
for (int i = 0; i 《 1000; i++) {
new Thread(new Runnable() {
@Override
public void run() {
Counter.inc();
}
}).start();
}
// 方法返回活动线程的当前线程的线程组中的数量---主线程下
while (Thread.activeCount() 》 1) // 保证前面的线程都执行完
Thread.yield(); //当一个线程使用了这个方法之后,它就会把自己CPU执行的时间让掉,让自己或者其它的线程运行。
// 这里每次运行的值都有可能不同,可能为1000
System.out.println(“运行结果:Counter.count=” + Counter.count);
}
}
评论
查看更多