前面说到了Java中的同步问题 下面通过一个小小的实例程序来演示Java中的同步方法 其中对前文提到的Counter类做了稍微的修改
public class Counter {
private int c =
public void increment() {
System out println( before increment c = + c)
c++
try {
Thread sleep( )
} catch (InterruptedException e) {
e printStackTrace()
}
System out println( after increment c = + c)
}
public void decrement() {
System out println( before decrement c = + c)
c
try {
Thread sleep( )
} catch (InterruptedException e) {
e printStackTrace()
}
System out println( after decrement c = + c)
}
public int value() {
return c
}
}
在上面的Counter类的实现中 分别对increment和decrement方法中增加了sleep( )的调用 这样做的目的是为了放大两个线程对同一对象的方法调用时的交错效果
下面是两个线程 在ThreadA中调用了 次increment()方法 在ThreadB中调用了 次decrement()方法
Thread
public class ThreadA implements Runnable {
private Counter c
public ThreadA(Counter c) {
this c = c
}
@Override
public void run() {
for (int i = i <i++) {
this c increment()
}
}
}
ThreadB
public class ThreadB implements Runnable {
private Counter c
public ThreadB(Counter c) {
this c = c
}
@Override
public void run() {
for (int i = i <i++) {
this c decrement()
}
}
}
主程序如下 其中生成了两个线程threadA和ThreadB 他们共享Counter c
public class Main {
public static void main(String[] args) {
Counter c = new Counter()
ThreadA a = new ThreadA(c)
ThreadB b = new ThreadB(c)
Thread threadA = new Thread(a)
Thread threadB = new Thread(b)
threadA start()
threadB start()
}
}
执行上面的代码 可能的结果如下
before increment c =
before decrement c =
after increment c =
before increment c =
after decrement c =
before decrement c =
after increment c =
before increment c =
after decrement c =
before decrement c =
after increment c =
before increment c =
after decrement c =
before decrement c =
after increment c =
before increment c =
after decrement c =
before decrement c =
after increment c =
before increment c =
after decrement c =
before decrement c =
after increment c =
before increment c =
after increment c =
before increment c =
after decrement c =
before decrement c =
after decrement c =
before decrement c =
after increment c =
before increment c =
after increment c =
before increment c =
after decrement c =
before decrement c =
after increment c =
after decrement c =
before decrement c =
after decrement c =
从上面的输出结果中我们不难看出出现了严重的交错现象! 在increment或者是decrement方法中输出before和after本应该是成对连续出现的 但输出结果却不是如此
将上面代码的increment()和decrement()方法用synchronized 修饰后 重新运行该程序 输出结果如下
before increment c =
after increment c =
before increment c =
after increment c =
before decrement c =
after decrement c =
before increment c =
after increment c =
before decrement c =
after decrement c =
before decrement c =
after decrement c =
before decrement c =
after decrement c =
before decrement c =
after decrement c =
before increment c =
after increment c =
before decrement c =
after decrement c =
before decrement c =
after decrement c =
before decrement c =
after decrement c =
before decrement c =
after decrement c =
before increment c =
after increment c =
before decrement c =
after decrement c =
before increment c =
after increment c =
before increment c =
after increment c =
before increment c =
after increment c =
before increment c =
after increment c =
before increment c =
after increment c =
这样输出结果和没有增加synchronized修饰符时的大不相同 单独一次的increment和decrement方法并没有出现交错的现象 只是连续 次的increment()和decrement ()有交错(这个不是synchronized能解决的问题)
至少 我们从上面的实例程序中可以看到synchronized方法的作用了
lishixinzhi/Article/program/Java/hx/201311/26369
线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。
另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。
一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。线程也有就绪、阻塞和运行三种基本状态。
就绪状态是指线程具备运行的所有条件,逻辑上可以运行,在等待处理机运行状态是指线程占有处理机正在运行阻塞状态是指线程在等待一个事件(如某个信号量),逻辑上不可执行。每一个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。
线程是程序中一个单一的顺序控制流程。进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指运行中的程序的调度单位。在单个程序中同时运行多个线程完成不同的工作,称为多线程。
同步就是只能A走完某一段然后停下,让B开始走一段再停下,再让A走。。如此往复。简单理解就是,必须是一段程序执行完后才能执行后面的程序。。
异步就是,同一时间可能A和B同时都在往终点赶,此时不存在先后顺序,就是说,两个程序可以同时执行,称为异步。
一般有两种方法同步方法和同步代码块假设P1、P2是同一个类的不同对象,这个类中定义了以下几种情况的同步块或同步方法,P1、P2就都可以调用它们。
1.把synchronized当作函数修饰符时,示例代码如下:
PublicsynchronizedvoidmethodAAA()
{
//….
}
这也就是同步方法,那这时synchronized锁定的是哪个对象呢?它锁定的是调用这个同步方法对象。也就是说,当一个对象P1在不同的线程中执行这个同步方法时,它们之间会形成互斥,达到同步的效果。但是这个对象所属的Class所产生的另一对象P2却可以任意调用这个被加了synchronized关键字的方法。
上边的示例代码等同于如下代码:
publicvoidmethodAAA()
{
synchronized(this)//(1)
{
//…..
}
}
(1)处的this指的是什么呢?它指的就是调用这个方法的对象,如P1。可见同步方法实质是将synchronized作用于objectreference。――那个拿到了P1对象锁的线程,才可以调用P1的同步方法,而对P2而言,P1这个锁与它毫不相干,程序也可能在这种情形下摆脱同步机制的控制,造成数据混乱:(
2.同步块,示例代码如下:
publicvoidmethod3(SomeObjectso)
{
synchronized(so)
{
//…..
}
}
这时,锁就是so这个对象,谁拿到这个锁谁就可以运行它所控制的那段代码。当有一个明确的对象作为锁时,就可以这样写程序,但当没有明确的对象作为锁,只是想让一段代码同步时,可以创建一个特殊的instance变量(它得是一个对象)来充当锁:
classFooimplementsRunnable
{
privatebyte[]lock=newbyte[0]//特殊的instance变量
PublicvoidmethodA()
{
synchronized(lock){//…}
}
//…..
}
注:零长度的byte数组对象创建起来将比任何对象都经济――查看编译后的字节码:生成零长度的byte[]对象只需3条 *** 作码,而Objectlock=newObject()则需要7行 *** 作码。
3.将synchronized作用于static函数,示例代码如下:
ClassFoo
{
publicsynchronizedstaticvoidmethodAAA()//同步的static函数
{
//….
}
publicvoidmethodBBB()
{
synchronized(Foo.class)//classliteral(类名称字面常量)
}
}
代码中的methodBBB()方法是把classliteral作为锁的情况,它和同步的static函数产生的效果是一样的,取得的锁很特别,是当前调用这个方法的对象所属的类(Class,而不再是由这个Class产生的某个具体对象了)。
记得在《EffectiveJava》一书中看到过将Foo.class和P1.getClass()用于作同步锁还不一样,不能用P1.getClass()来达到锁这个Class的目的。P1指的是由Foo类产生的对象。
可以推断:如果一个类中定义了一个synchronized的static函数A,也定义了一个synchronized的instance函数B,那么这个类的同一对象Obj在多线程中分别访问A和B两个方法时,不会构成同步,因为它们的锁都不一样。A方法的锁是Obj这个对象,而B的锁是Obj所属的那个Class。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)