五、线程的同步(加锁 )
1、为什么需要同步
取得0~10的和采用相同的线程对象启用两个线程进行计算 ( 共享一个对象启动两个线程 )
public class ThreadTest {
public static void main(String[] args) {
Runnable r1 = new Processor();
Thread t1 = new Thread(r1, "t1");
t1.start();
Thread t2 = new Thread(r1, "t2");
t2.start();
}
}
class Processor implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
int s = 0;
for (int i = 0; i < 10; i++) {
s += i;
}
System.out.println(Thread.currentThread().getName() + ",s=" + s);
}
}
以上 t1和 t2并发执行, s为每个线程的局部变量,位于各自的栈帧中,因为栈帧中的数据
是不会互相干扰的,所有计算结果都为45
取得0~10的和采用两个线程进行计算, 将 s改为成员变量(共享一个对象启动两个线程 )
public class ThreadTest {
public static void main(String[] args) {
Runnable r1 = new Processor();
Thread t1 = new Thread(r1, "t1");
t1.start();
Thread t2 = new Thread(r1, "t2");
t2.start();
}
}
class Processor implements Runnable {
private int s = 0;
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 10; i++) {
s += i;
}
System.out.println(Thread.currentThread().getName() + ",s=" + s);
}
}
为什么出现以上的问题,因为共享了同一个对象的成员变量s,两个线程同时对其进行操作,
所以产生了问题,此时称为此时 Processor为线程不安全的,如果想得到正确的结果,必须
采用线程同步,加锁,该变量不能共享使用。
2、使用线程同步
线程同步,指某一个时刻,指允许一个线程来访问共享资源,线程同步其实是对对象加锁,
如果对象中的方法都是同步方法, 那么某一时刻只能执行一个方法, 采用线程同步解决以上
的问题, 我们只要保证线程一操作s时, 线程2不允许操作即可,只有线程一使用完成 s后,
再让线程二来使用s变量
public class ThreadTest {
public static void main(String[] args) {
Runnable r = new Processor();
Thread t1 = new Thread(r, "t1");
t1.start();
Thread t2 = new Thread(r, "t2");
t2.start();
}
}
class Processor implements Runnable {
private int s = 0;
@Override
public synchronized void run() {
// TODO Auto-generated method stub
synchronized(this){
for (int i = 0; i < 10; i++) {
s += i;
}
System.out.println(Thread.currentThread().getName() + ",s=" + s);
s= 0;
}
}
}
以上示例, 如果不采用线程同步如何解决?可以让每个线程创建一个对象, 这样在堆中就不
会出现对象的状态共享了,从而可以避免线程安全问题
3、为每一个线程创建一个对象来解决线程安全问题
public class ThreadTest {
public static void main(String[] args) {
Runnable r1 = new Processor();
Thread t1 = new Thread(r1, "t1");
t1.start();
Runnable r2 = new Processor12();
Thread t2 = new Thread(r2, "t2");
t2.start();
}
}
class Processor implements Runnable {
private int s = 0;
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 10; i++) {
s += i;
}
System.out.println(Thread.currentThread().getName() + ",s=" + s);
}
}