线程 | 同步 (synchronized) | 异步 (asynchronized) |
---|---|---|
特点 | A线程要请求某个资源,但是此资源正在被B线程使用中,因为同步机制存在,A线程请求不到,怎么办,A线程只能等待下去 | A线程要请求某个资源,但是此资源正在被B线程使用中,因为没有同步机制存在,A线程仍然请求的到 |
安全 | 最最安全,最保险的 thread-safe,(线程安全) | 异步不安全,容易导致死锁 |
使用 | 要跨线程维护正确的可见性,只要在几个线程之间共享非 final 变量,就必须使用synchronized(或 volatile)以确保一个线程可以看见另一个线程做的更改。 | —— |
实现 | 1、ThreadLocal 2、synchronized( ) 3、wait()与 notify() 4、volatile | —— |
表现形式 | 1、同步代码块,被同步关键字封装的代码就是同步代码块;2、同步函数,被同步关键字修饰的函数就是同步函数。 | —— |
锁 | synchronzied(obj){ }同一个锁 | synchronzied(new Object){ } 不是同一个锁 |
锁特性 | 互斥(mutual exclusion) | 可见性(visibility) |
---|---|---|
特点 | 即一次只允许一个线程持有某个特定的锁,因此可使用该特性实现对共享数据的协调访问协议,这样,一次就只有一个线程能够使用该共享数据 | 要更加复杂一些,它必须确保释放锁之前对共享数据做出的更改对于随后获得该锁的另一个线程是可见的 —— (如果没有同步机制提供的这种可见性保证,线程看到的共享变量可能是修改前的值或不一致的值,这将引发许多严重问题) |
sleep() | wait() | |
---|---|---|
来源 | 线程类(Thread)的方法 | Object类的方法 |
特点 | 导致此线程暂停执行指定时间,把执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁 | 对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。 |
ThreadLocal 保证不同线程拥有不同实例,相同线程一定拥有相同的实例,即为每一个使用该变量的线程提供一个该变量值的副本,每一个线程都可以独立改变自己的副本,而不是与其它线程的副本冲突。
优势:提供了线程安全的共享对象与其它同步机制的区别:同步机制是为了同步多个线程对相同资源的并发访问,是为了多个线程之间进行通信;而ThreadLocal 是隔离多个线程的数据共享,从根本上就不在多个线程之间共享资源,这样当然不需要多个线程进行同步了。
注: 部分引用于网络
class Demo{
//非同步
static void method(Thread thread){
System.out.println("begin "+thread.getName());
try{
Thread.sleep(2000);
}catch(Exception ex){
ex.printStackTrace();
}
System.out.println("end "+thread.getName());
}
//同步方式一:同步方法
synchronized static void method1(Thread thread){//这个方法是同步的方法,每次只有一个线程可以进来
System.out.println("begin "+thread.getName());
try{
Thread.sleep(2000);
}catch(Exception ex){
ex.printStackTrace();
}
System.out.println("end "+thread.getName());
}
//同步方式二:同步代码块
static void method2(Thread thread){
synchronized(Demo.class) {
System.out.println("begin "+thread.getName());
try{
Thread.sleep(2000);
}catch(Exception ex){
ex.printStackTrace();
}
System.out.println("end "+thread.getName());
}
}
//同步方式三:使用同步对象锁
private static Object _lock1=new Object();
private static byte _lock2[]={};//据说,此锁更可提高性能。源于:锁的对象越小越好
static void method3(Thread thread){
synchronized(_lock1) {
System.out.println("begin "+thread.getName());
try{
Thread.sleep(2000);
}catch(Exception ex){
ex.printStackTrace();
}
System.out.println("end "+thread.getName());
}
}
public static void main(String[] args){
//启动3个线程,这里用了匿名类
for(int i=0;i<3;i++){
new Thread(){
public void run(){
method(this);
//method1(this);
//method2(this);
//method3(this);
}
}.start();
}
}
}
public class Demo{
public static void main(String[] args){
Callme target=new Callme();
Caller ob1=new Caller(target,"Hello");
Caller ob2=new Caller(target,"Synchronized");
Caller ob3=new Caller(target,"World");
}
}
class Callme{
synchronized void test(){
System.out.println("测试是否是:一旦一个线程进入一个实例的任何同步方法,别的线程将不能进入该同一实例的其它同步方法,但是该实例的非同步方法仍然能够被调用");
}
void nonsynCall(String msg){
System.out.println("[" + msg + "]");
}
synchronized void synCall(String msg){
System.out.println("[" + msg + "]");
}
}
class Caller implements Runnable{
String msg;
Callme target;
Thread t;
Caller(Callme target,String msg){
this.target=target;
this.msg=msg;
t=new Thread(this);
t.start();
}
public void run() {
// TODO Auto-generated method stub
//target.nonsynCall(msg);
target.synCall(msg);
target.test();
}
}