一、synchronized同步方法
论:“线程安全”与“非线程安全”是多线程的经典问题。synchronized()方法就是解决非线程安全的。
1、方法内的变量为线程安全
public void addI(String username) {
try {
int num = 0; \\方法内的变量为线程安全
if (username.equals("a")) {
num = 100;
System.out.println("a set over!");
Thread.sleep(2000);
} else {
num = 200;
System.out.println("b set over!");
}
System.out.println(username + " num=" + num);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
2、实例变量非线程安全
public class HasSelfPrivateNum {
private int num = 0; \\实例变量非线程安全
public void addI(String username) {
try {
if (username.equals("a")) {
num = 100;
System.out.println("a set over!");
Thread.sleep(2000);
} else {
num = 200;
System.out.println("b set over!");
}
System.out.println(username + " num=" + num);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} }
解决方法: 方法前加synchronized关键字。
public class HasSelfPrivateNum { private int num = 0; synchronized public void addI(String username) {
..............
} }
3、多个对象多个锁
HasSelfPrivateNum.java
public class HasSelfPrivateNum { private int num = 0; synchronized public void addI(String username) {
try {
if (username.equals("a")) {
num = 100;
System.out.println("a set over!");
Thread.sleep(2000);
} else {
num = 200;
System.out.println("b set over!");
}
System.out.println(username + " num=" + num);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} }
ThreadA
public class ThreadA extends Thread { private HasSelfPrivateNum numRef; public ThreadA(HasSelfPrivateNum numRef) {
super();
this.numRef = numRef;
} @Override
public void run() {
super.run();
numRef.addI("a");
} }
ThreadB
public class ThreadB extends Thread { private HasSelfPrivateNum numRef; public ThreadB(HasSelfPrivateNum numRef) {
super();
this.numRef = numRef;
} @Override
public void run() {
super.run();
numRef.addI("b");
} }
RUN
public class Run { public static void main(String[] args) { HasSelfPrivateNum numRef1 = new HasSelfPrivateNum();
HasSelfPrivateNum numRef2 = new HasSelfPrivateNum(); ThreadA athread = new ThreadA(numRef1);
athread.start(); ThreadB bthread = new ThreadB(numRef2);
bthread.start(); } }
结果:创建了2个业务实例,产生2个锁,所以运行结果是异步的。同步为synchronized 异步:asynchronized
4、synchronized 锁重入
当一个线程得到一个对象锁时,再次请求该对象锁时是可以再次得到该对象的锁的。继承关系也可重入锁。
当一个线程执行发生异常时,其持有的锁会自动释放。
同步不具有继承性。的在子类方法中添加synchronized的关键字。
public class HasSelfPrivateNum {
synchronized public void service1() {
System.out.println("service1");
service2();
} synchronized public void service2() {
System.out.println("service2");
service3();
} synchronized public void service3() {
System.out.println("service3");
}
}
HasSelfPrivateNum.java
public class mYThread extends Thread {
@Override
public void run() {
HasSelfPrivateNum hspn=new HasSelfPrivateNum();
hspn.service1();
}
public static void main(String[] args) {
mYThread mYThread=new mYThread();
mYThread.start();
}
}
mYThread.java
二、synchronized同步快
synchronized同步方法持有锁后,如果长时间不释放,那另一个线程就必须长时间等待。。这种情况下synchronized同步快来解决
使用方法如图:
1、synchronized同步快之间具有同步性,当线程访问object的一个 synchronized(this)同步代码块时,其他线程对同一个object对象中所有其他的
synchronized(this)同步代码块的访问会被阻塞。
2、synchronized(this)同步代码块是锁定当前对象的。
1、synchronized同步快解决同步方法效率低得弊端
public class Task { private String getData1;
private String getData2; public synchronized void doLongTimeTask() {
try {
System.out.println("begin task");
Thread.sleep(3000);
getData1 = "长时间处理任务后从远程返回的值1 threadName="
+ Thread.currentThread().getName();
getData2 = "长时间处理任务后从远程返回的值2 threadName="
+ Thread.currentThread().getName();
System.out.println(getData1);
System.out.println(getData2);
System.out.println("end task");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Task
public class MyThread1 extends Thread { private Task task; public MyThread1(Task task) {
super();
this.task = task;
} @Override
public void run() {
super.run();
CommonUtils.beginTime1 = System.currentTimeMillis();
task.doLongTimeTask();
CommonUtils.endTime1 = System.currentTimeMillis();
} }
MyThread1
public class MyThread2 extends Thread { private Task task; public MyThread2(Task task) {
super();
this.task = task;
} @Override
public void run() {
super.run();
CommonUtils.beginTime2 = System.currentTimeMillis();
task.doLongTimeTask();
CommonUtils.endTime2 = System.currentTimeMillis();
} }
MyThread2
public class CommonUtils { public static long beginTime1;
public static long endTime1; public static long beginTime2;
public static long endTime2;
}
CommonUtils
public class Run { public static void main(String[] args) {
Task task = new Task(); MyThread1 thread1 = new MyThread1(task);
thread1.start(); MyThread2 thread2 = new MyThread2(task);
thread2.start(); try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
} long beginTime = CommonUtils.beginTime1;
if (CommonUtils.beginTime2 < CommonUtils.beginTime1) {
beginTime = CommonUtils.beginTime2;
} long endTime = CommonUtils.endTime1;
if (CommonUtils.endTime2 > CommonUtils.endTime1) {
endTime = CommonUtils.endTime2;
} System.out.println("耗时:" + ((endTime - beginTime) / 1000));
}
}
Run
修改Task
public class Task { private String getData1;
private String getData2; public void doLongTimeTask() {
try {
System.out.println("begin task");
Thread.sleep(3000); String privateGetData1 = "长时间处理任务后从远程返回的值1 threadName="
+ Thread.currentThread().getName();
String privateGetData2 = "长时间处理任务后从远程返回的值2 threadName="
+ Thread.currentThread().getName(); synchronized (this) {
getData1 = privateGetData1;
getData2 = privateGetData2;
} System.out.println(getData1);
System.out.println(getData2);
System.out.println("end task");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}