publicclass HasSelfPrivateNum {
privateintindex = -1;//成员变量
publicvoid addI(String
username){
try {
intnum = 0;//方法内变量
if(username.equals("a")){
num = 100;
index = 1111;
System.out.println("a is set over 100");
Thread.sleep(2500);
}else{
num = 200;
index = 222;
System.out.println("b is set over 200");
}
System.out.println("username = "+username
+",num = "+num+"---->index="+index);
} catch (Exception
e) {
thrownew RuntimeException(e);
}
}
}
publicclass ThreadA
extends Thread{
private HasSelfPrivateNum
has;
public ThreadA(HasSelfPrivateNum
has){
this.has =
has;
}
@Override
publicvoid run() {
has.addI("a");
}
}
publicclass ThreadB
extends Thread {
private
HasSelfPrivateNum has;
public ThreadB(HasSelfPrivateNum
has){
this.has =
has;
}
@Override
publicvoid run() {
this.has.addI("b");
}
}
publicclass HasSelfPrivateNumRn {
publicstaticvoid main(String[]
args) {
HasSelfPrivateNum
has = new HasSelfPrivateNum();
ThreadA
a = new ThreadA(has);
ThreadB
b = new ThreadB(has);
a.start();
b.start();
}
}
结果:
解析:因为方法内都是各自线程自我调用,没有共同资源;成员变量出现了(公共资源),因为线程共同访问+沉睡,导致了错误,同时多线程的调用导致了整个打印的错乱。
-------
案例二:方法级别同步,保证线程安全性
修改:在HasSelfPrivateNum类中的addI()方法加上synchronized关键字,产生正确结果(同时造成线程的堵塞)。多个线程同时持有一个对象的锁,看线程强占速度,所以日志没有交叉,数据正确。
结果【实现线程安全】:
案例三:多个对象多个锁
publicclass HasSelfPrivateNumRn2 {
publicstaticvoid main(String[]
args) {
HasSelfPrivateNum
t1 = new HasSelfPrivateNum();
HasSelfPrivateNum
t2 = new HasSelfPrivateNum();
ThreadA
a = new ThreadA(t1);
ThreadB
b = new ThreadB(t2);
a.start();
b.start();
}
}
结果:
解析:声明了t1和t2两个对象,在a线程中调取t1对象,拥有的是t1对象的锁,而b线程中调取t2对象,拥有的是t2对象的锁。关键字synchronized取得的锁都是对象锁,这样他们就互不影响,t1和t2的信息都保存在自己的线程栈中,对其他线程不可见,所有a和b并发执行(log交叉)。
案例四:类锁【继续修改上述案例】
publicclass HasSelfPrivateNum {
privatestaticintindex
= -1;//静态化
//方法静态化
publicstaticsynchronizedvoid
addI(String username){
try {
intnum = 0;
if(username.equals("a")){
num = 100;
index = 1111;
System.out.println("a is set over 100");
Thread.sleep(2500);
}else{
num = 200;
index = 222;
System.out.println("b is set over 200");
}
System.out.println("username = "+username
+",num = "+num+"---->index="+index);
} catch (Exception
e) {
thrownew RuntimeException(e);
}
}
}
结果:
解析:如果在addI方法上加上static关键字,,表示锁定class类。不管声明多少个MultiThread引用,printNum方法跟随类存放在堆上,线程间会共享资源,输出结果会等m1信息输出结束之后才会开始输出m2信息。
总结:一个对象一把锁(实现对象上互斥);在静态方法上synchronized代表的是类的锁(实现类上互斥)。
案例五:
publicclass ThreeSynchronizedTask {
publicsynchronizedvoid printA(){
System.out.println(Thread.currentThread().getName()+"--printA--"+System.currentTimeMillis());
}
publicsynchronizedvoid printB(){
try {
Thread.sleep(2000);
} catch (InterruptedException
e) {
//
TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"--printB--"+System.currentTimeMillis());
}
publicsynchronizedvoid printC(){
System.out.println(Thread.currentThread().getName()+"--printC--"+System.currentTimeMillis());
}
}
publicclass Ta
extends Thread{
private ThreeSynchronizedTask
task;
public Ta(ThreeSynchronizedTask
task){
this.task =
task;
}
@Override
publicvoid run() {
task.printA();
task.printB();
task.printC();
}
}
publicclass Tb
extends Thread{
private ThreeSynchronizedTask
task;
public Tb(ThreeSynchronizedTask
task){
this.task =
task;
}
@Override
publicvoid run() {
task.printA();
task.printB();
task.printC();
}
}
publicclass ThreeSynchronizedTaskRn {
publicstaticvoid main(String[]
args) {
ThreeSynchronizedTask
task = new
ThreeSynchronizedTask();
Ta
a = new Ta(task);
a.setName("A");
Tb
b = new Tb(task);
b.setName("B");
a.start();
b.start();
}
}
结果:
解析:
线程强占锁之后,执行synchronized方法,然后如果有持续的synchronized方法会继续持有,否则释放掉抢占的锁。也会出现线程交替执行的程序。
|