线程的同步也可以称为并发,由于进程是处理机分配资源的最小单位,
就会出现多个线程共同享用一个资源的想象,在带来方便的同时也带来了访问资源冲突这个严重的问题,
JAVA语言在提供了专门机制解决这种冲突,有效的避免了同一个数据对象被多个线程同时访问
关键字synchronized,在多线程情况下,可以确保资源安全,即线程安全
以前提到的HashTable线程安全,HashMap线程不安全,说的也就是线程同步问题
HashTable的put方法用synchronized关键字修饰,所以它的线程安全
同步又分为了同步块以及同步方法
同步方法:方法前面添加synchronized关键字
同步块:synchronized(引用类型|this|类.class){ }
利用关键字synchronize来解决之前遗留的线程不安全的问题
在博文-[线程的阻塞+通过外部干涉终止一个线程]中,当加入线程休眠模拟网络延迟时,出现了多线程并发错误
1.同步方法
解决方法其实很简单,见代码
public class SynDemo01 {
public static void main(String[] args) {
web1 web = new web1();
Thread t1 = new Thread(web);
Thread t2 = new Thread(web);
t1.start();
t2.start();
}
}
class web1 implements Runnable{
public int num=10;
private boolean flag=true;
@Override
public void run() {
while(flag){
test2();
}
}
/**
* 线程不安全
*/
public void test1(){
if(num<=0){
flag=false;
return;
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"抢到了 "+num--);
}
/**
* 线程安全
*/
public synchronized void test2(){
if(num<=0){
flag=false;
return ;
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"抢到了 "+num--);
}
}
为方法添加关键字就可以使资源上锁,也就是当t1,t2这两个线程都需要进入到test2方法时,当其中一个进入以后,
就会阻止另一个线程也进入,这样就不会出现线程不安全的问题了
当你的方法添加了synchronize关键字以后,只能被一个线程访问
2.同步块
在方法签名中添加关键字,是将整个方法体都锁定了,所有方法体都只允许一个线程访问
而同步块可以只将需要锁定的部分代码锁定起来
使用同步块就带来了锁定资源和锁定范围的问题
锁定范围不能过大,造成资源利用率低下,也不能过小,没有锁定正确线程还是不安全的
这也是解决多线程并发的难点所在
通过代码实例操作,可以看出来线程安全要比线程不安全慢,线程安全有等待,效率低