Java 多线程

当两个线程可能会访问一个对象的某个属性值(field)(包括读写),就要同步所有的读写该属性值(field)的所有方法。(
[list]
[*]当然通过反射直接修改该属性值,或者通过未同步的方法仍旧可以使该对象的值处于不稳定(unstable)的状态
[*]假如没有同步被多个线程访问对象属性的方法,有可能其中的一个方法正处于执行当中,并修改了该对象的一些属性值,但是还没有完全执行完,并返回,此时的中属性值并不稳定,完整。如果此时另一个线程访问到了这个处于不稳定的属性值,将得到bug。
[/list])

现代的处理器当中都有多个内核,每个内核中可能会缓存每个线程中的值,如果多个线程需要访问同一个值,而这个值的修改由于缓存到cpu的寄存器当中,造成其他访问该属性值的线程对此对象的更改不可见,并由此产生bug,由此可以用volatile关键字强迫jvm关闭优化,将该属性值写入到内存中,并由各个线程从内存中读取(但是并不建议除了多线程专家之外的人员用volatile关键字,尽量使用synchronized关键字来同步数据)。synchronized 关键字(包括synchronized block)同样有这种效果。

synchronized 方法,和synchronized block会排出其他synchronized 方法或者synchronized block对其加锁的对象的访问,但是并不排除被其加锁对象的非synchronized方法的访问。(可以看下面的程序示例)

synchronized block (synchronized 块),和synchronized 方法的区别:
synchronized block 可以用其他对象的锁来同步块内的操作,而synchronized方法,只能对拥有其方法的对象加锁来同步方法内的操作。所以某种程度上synchronied(this){}和synchronized 方法的作用是一样的。

最好不要将ReentrantLock和synchronized关键字混搭在一个对象里,因为彼此无法排出(exclude)对方的操作,也就无法有效地对同一个对象进行同步。


package interaction.thinkinjava.concurrency;

import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class EX15Copy {
public static void main(String[] args) {
new Timer().schedule(new TimerTask() {

@Override
public void run() {
System.out.println("System is ready to exit");
System.exit(0);
}
}, 5000);

ExecutorService es = Executors.newCachedThreadPool();
Model m = new Model();
es.execute(m.getYourTask(0));
es.execute(m.getYourTask(1));
es.execute(m.getYourTask(2));
es.execute(m.getYourTask(3));
}

}


class Model{
private class Task implements Runnable{
private final int funToCall;
Task(int functionCode){
this.funToCall = functionCode;
}
@Override
public void run() {
switch(funToCall){
case 0:
while(true){
f();
}
case 1:
while(true){
h();
}
case 2:
while(true){
g();
}
case 3:
while(true){
k();
}
}
}

}

public Runnable getYourTask(int funCode){
return new Task(funCode);
}

public synchronized void f(){
System.out.println("f() function get the lock");
try {
TimeUnit.MILLISECONDS.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread.yield();
System.out.println("f() function done its job");
}

public synchronized void h(){
System.out.println("h() function get the lock");
try {
TimeUnit.MILLISECONDS.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread.yield();
System.out.println("h() function done its job");
}

public synchronized void g(){
System.out.println("g() function get the lock");
try {
TimeUnit.MILLISECONDS.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread.yield();
System.out.println("g() function done its job");
}
public void k(){
System.out.println("k() function run");
try {
TimeUnit.MILLISECONDS.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread.yield();
System.out.println("k() function done its job");
}
}


结果

f() function get the lock
k() function run
f() function done its job
g() function get the lock
k() function done its job
k() function run
g() function done its job
k() function done its job
k() function run
g() function get the lock
g() function done its job
.....

可以看出被synchronized修饰的f,h,g方法都是有顺序的访问,而没有被synchronized关键字修饰的k方法则是穿插在其中
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值