java线程

 
  • notify()notifyAll()wait()必须在锁住该对象的同步语句内调用。

摘录Jdoc的说明:

This method should only be called by a thread that is the owner of this object's monitor. A thread becomes the owner of the object's monitor in one of three ways:

By executing a synchronized instance method of that object.

By executing the body of a synchronized statement that synchronizes on the object.

For objects of type Class, by executing a synchronized static method of that class.

Only one thread at a time can own an object's monitor.

但是没有synchronized 同样可以通过编译。

----------------------------------------------------------------------------------------------------------

  • synchronzied关键字的使用

public class Two

{

public static void  main(String[] args)

{

Abc abc=new Abc();

new Thread(abc).start();

for(int i=0;i<1000;i++);

new Thread(abc).start();

}

}

 

 

class Abc implements Runnable

{

 

public  void  print()

{

synchronized(this){

int i=0;

while(i<100)

{System.out.println("in print1");

System.out.println("in print2");

i++;

}

}}

public void print1()

{int i=0;

while (i < 100) {System.out.println("anthor");

i++;

}

}

 

public void run()

{

 

System.out.println("run");

if(j==0)

{j++;

print();

}

else

{print1();}

}

static int j; 

}

注:synchronizedthis)并不能阻止非synchronized方法执行,

上面代码会打印出

in print1

anthor

in print2

synchronizedthis)改成 synchronized print()也有相同效果。

 

代码改成这样也有相同效果

public class Two

{

public static void  main(String[] args)

{

Abc abc=new Abc();

new Thread(abc).start();

for(int i=0;i<1000;i++);

new Thread(abc).start();

}

}

 

 

class Abc implements Runnable

{

Object lock = new Object();

public   void  print()

{

synchronized(this){

int i=0;

while(i<100)

{System.out.println("in print1");

System.out.println("in print2");

i++;

}}

}

public void print1()

{synchronized(lock){

int i=0;

while (i < 100) {System.out.println("anthor");

i++;

}}

}

 

public void run()

{

 

System.out.println("run");

if(j==0)

{j++;

print1();

}

else

{print();}

}

static int j; 

 

}

注:synchronizedthis)和synchronized (lock) 并不会互斥,注意synchronized只作用于对象自身,不对对象里面的成员起作用。

 

 

线程的又一个同步。

synchronized(ClassName.class)

static synchronized method()

它们为类级的同步,相对应于synchronized(this)和synchronized method()。

它们是两个级别的访问,synchronized(ClassName.class)和static synchronized method()并不会限制对于对象级的同步访问。可以把它们和起来用:如synchronzied methed(){synchronized(ClassName.class){}},但这么奇怪的写法有什么用,没深究。

----------------------------------------------------------------------------------------------------------

  • 内部类的同步问题:

public class outer{

private void printI()

{

synchronized (this)

{while(true)

{

System.out.println(i);

i++;

}

}

}

 

public class inner implements Runnable

{

public void run()

{

System.out.println("Create");

while(true)

{

System.out.println("inner"+i);

i++;

}

}

}

}

一般在打印“Create”的地方,会表现出同步问题。

 

虽然在printI()方法中,用synchronizedthis)来锁定对象,但内部类的run()不需要外部类的对象锁;所以仍然会同时访问i变量。用下面方法可以锁定:

public void run()

{

System.out.println("Create");

synchronized(outer.this)

{

while(true)

{

System.out.println("inner"+i);

i++;

}

}

}

}

----------------------------------------------------------------------------------------------------------

Java中,object.wait()并不是指object指向的对象进入等待状态。

而是,当前线程(可以是基于object这个对象,也可以是别的对象),把自己加入到object这个对象的等待池中,等待其它线程通过object.notify()唤醒它。

----------------------------------------------------------------------------------------------------------

假设有线程 Thread t

可以调用t.join()来使当前线程等待线程t运行结束后再继续执行。

t.join()相当于一个阻塞方法,要在 t.start()语句之后执行,在 t.start()语句之前执行没有效果。

 

-------------------------------------------------------------------------------------------------

volatile关键字释义:

首先每个线程都有自己一个工作内存区,多个线程共享一个主内存区。线程中的本地变量存在自己的内存区中,如for(int i=0;i<100;i++){this.i=i;},其中i就存在线程工作内存中,即每个线程都有一个,不用也不能加volatile关键字,this.i就是共享变量。而共享的变量就存在主内存区里,但Java线程为了提高效率,会把共享变量拷贝到自己的工作区中,这就产生了变量一致性的问题。

java提供的一种方法是互斥访问,互斥访问会在加锁和解锁中维持变量的一致性,另一种就是volatile关键字。

 

java language specification中的一个例子,有类如下:

class Test {

static int i = 0, j = 0;

static void one() { i++; j++; }

static void two() {

System.out.println("i=" + i + " j=" + j);

}

}

有两个线程,一个不停调用 one(),一个不停调用 two(),则有可能出现这种情况,打印出来的j比i还大。因为这时线程对共享变量的更新是无序的。

1.使用同步方法:

class Test {

static int i = 0, j = 0;

static synchronized void one() { i++; j++; }

static synchronized void two() {

System.out.println("i=" + i + " j=" + j);

}

}

这就不用我介绍了,i和j始终一样大。

2.使用volatile

class Test {

static volatile int i = 0, j = 0;

static void one() { i++; j++; }

static void two() {

System.out.println("i=" + i + " j=" + j);

}

}

这样能允许one()和two()并发执行,同时使one()如字面一样执行。这一般能使打印出来的j不会大于i,在更新j之前会先更新i。但有可能打印出来的j比i大很多,因为one()可能在two获取i和j之间执行了很多次。

 

说明一下:

java language specification中的例子不好,有点晦涩,但我认为volatile的作用就是保证任何时候主内存的i都大于等于j。two()中出现j比i大很多,只是因为它访问的是不同时刻的主内存。

还有一点,就是volatile能防止编译器对变量进行优化,每次共享变量都到主内存。如果线程不到主内存中读,变量的值就会不正确。

强制线程到主存中读,应该也包含上面wulemale所说的,变量被程序外部改变的情况。

 

 

而且还有一点要注意,java的这样设计是因为跨平台。为了让更多的java program implement能够在不同的平台利用硬件特性进行优化。不过这样会导致程序的不一致行为。为了保证每次执行都按正确方式。sun 建议使用synchronized来强制在同步块中使用共享变量,这样可以保证程序不会因为使用不同的虚拟机而导致问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值