❶ java 被关键字 synchronized修饰的方法有什么特点关键字synchronized有什么作用
Java语言的synchronized关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。
一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
❷ java线程同步问题,用了synchronized关键字后不能实现锁定
你要把你的Timer t=new Timer()设置为static的,不然下面代码中你创建两个TestSync对象,也就有了两个t,然后你的两个线程分别调用不同的t,不能实现锁定,下面是正确代码
---------------------------------------------
public class TestSync extends Thread {
/**
* @param args
*/
static Timer t = new Timer();
public static void main(String[] args) {
TestSync t1 = new TestSync();
TestSync t2 = new TestSync();
t1.setName("t1");
t2.setName("t2");
t1.start();
t2.start();
}
public void run() {
t.add(Thread.currentThread().getName());
}
}
class Timer {
private static int num = 0;
public synchronized void add(String name) {
num++;
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
System.out.println(name + "你是第" + num + "个访问Timer的线程");
}
}
❸ java多线程开发的同步机制有哪些
Java同步
标签: 分类:
一、关键字:
thread(线程)、thread-safe(线程安全)、intercurrent(并发的)
synchronized(同步的)、asynchronized(异步的)、
volatile(易变的)、atomic(原子的)、share(共享)
二、总结背景:
一次读写共享文件编写,嚯,好家伙,竟然揪出这些零碎而又是一路的知识点。于是乎,Google和翻阅了《Java参考大全》、《Effective Java Second Edition》,特此总结一下供日后工作学习参考。
三、概念:
1、 什么时候必须同步?什么叫同步?如何同步?
要跨线程维护正确的可见性,只要在几个线程之间共享非 final 变量,就必须使用 synchronized(或 volatile)以确保一个线程可以看见另一个线程做的更改。
为了在线程之间进行可靠的通信,也为了互斥访问,同步是必须的。这归因于java语言规范的内存模型,它规定了:一个线程所做的变化何时以及如何变成对其它线程可见。
因为多线程将异步行为引进程序,所以在需要同步时,必须有一种方法强制进行。例如:如果2个线程想要通信并且要共享一个复杂的数据结构,如链表,此时需要
确保它们互不冲突,也就是必须阻止B线程在A线程读数据的过程中向链表里面写数据(A获得了锁,B必须等A释放了该锁)。
为了达到这个目的,java在一个旧的的进程同步模型——监控器(Monitor)的基础上实现了一个巧妙的方案:监控器是一个控制机制,可以认为是一个
很小的、只能容纳一个线程的盒子,一旦一个线程进入监控器,其它的线程必须等待,直到那个线程退出监控为止。通过这种方式,一个监控器可以保证共享资源在
同一时刻只可被一个线程使用。这种方式称之为同步。(一旦一个线程进入一个实例的任何同步方法,别的线程将不能进入该同一实例的其它同步方法,但是该实例
的非同步方法仍然能够被调用)。
错误的理解:同步嘛,就是几个线程可以同时进行访问。
同步和多线程关系:没多线程环境就不需要同步;有多线程环境也不一定需要同步。
锁提供了两种主要特性:互斥(mutual exclusion) 和可见性(visibility)。
互斥即一次只允许一个线程持有某个特定的锁,因此可使用该特性实现对共享数据的协调访问协议,这样,一次就只有一个线程能够使用该共享数据。
可见性要更加复杂一些,documents它必须确保释放锁之前对共享数据做出的更改对于随后获得该锁的另一个线程是可见的 —— 如果没有同步机制提供的这种可见性保证,线程看到的共享变量可能是修改前的值或不一致的值,这将引发许多严重问题
小结:为了防止多个线程并发对同一数据的修改,所以需要同步,否则会造成数据不一致(就是所谓的:线程安全。如java集合框架中Hashtable和
Vector是线程安全的。我们的大部分程序都不是线程安全的,因为没有进行同步,而且我们没有必要,因为大部分情况根本没有多线程环境)。
2、 什么叫原子的(原子操作)?
Java原子操作是指:不会被打断地的操作。(就是做到互斥 和可见性?!)
那难道原子操作就可以真的达到线程安全同步效果了吗?实际上有一些原子操作不一定是线程安全的。
那么,原子操作在什么情况下不是线程安全的呢?也许是这个原因导致的:java线程允许线程在自己的内存区保存变量的副本。允许线程使用本地的私有拷贝进
行工作而非每次都使用主存的值是为了提高性能(本人愚见:虽然原子操作是线程安全的,可各线程在得到变量(读操作)后,就是各自玩
弄自己的副本了,更新操作(写操作)因未写入主存中,导致其它线程不可见)。
那该如何解决呢?因此需要通过java同步机制。
在java中,32位或者更少位数的赋值是原子的。在一个32位的硬件平台上,除了double和long型的其它原始类型通常都
是使用32位进行表示,而double和long通常使用64位表示。另外,对象引用使用本机指针实现,通常也是32位的。对这些32位的类型的操作是原
子的。
这些原始类型通常使用32位或者64位表示,这又引入了另一个小小的神话:原始类型的大小是由语言保证的。这是不对的。java语言保证的是原始类型的表
数范围而非JVM中的存储大小。因此,int型总是有相同的表数范围。在一个JVM上可能使用32位实现,而在另一个JVM上可能是64位的。在此再次强
调:在所有平台上被保证的是表数范围,32位以及更小的值的操作是原子的。
3、 不要搞混了:同步、异步
举个例子:普通B/S模式(同步)AJAX技术(异步)
同步:提交请求->等待服务器处理->处理完返回 这个期间客户端浏览器不能干任何事
异步:请求通过事件触发->服务器处理(这是浏览器仍然可以作其他事情)->处理完毕
可见,彼“同步”非此“同步”——我们说的java中的那个共享数据同步(synchronized)
一个同步的对象是指行为(动作),一个是同步的对象是指物质(共享数据)。
4、 Java同步机制有4种实现方式:(部分引用网上资源)
① ThreadLocal ② synchronized( ) ③ wait() 与 notify() ④ volatile
目的:都是为了解决多线程中的对同一变量的访问冲突
ThreadLocal
ThreadLocal 保证不同线程拥有不同实例,相同线程一定拥有相同的实例,即为每一个使用该变量的线程提供一个该变量值的副本,每一个线程都可以独立改变自己的副本,而不是与其它线程的副本冲突。
优势:提供了线程安全的共享对象
与其它同步机制的区别:同步机制是为了同步多个线程对相同资源的并发访问,是为了多个线程之间进行通信;而 ThreadLocal 是隔离多个线程的数据共享,从根本上就不在多个线程之间共享资源,这样当然不需要多个线程进行同步了。
volatile
volatile 修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。
优势:这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。
缘由:Java
语言规范中指出,为了获得最佳速度,允许线程保存共享成员变量的私有拷贝,而且只当线程进入或者离开同步代码块时才与共享成员变量的原
始值对比。这样当多个线程同时与某个对象交互时,就必须要注意到要让线程及时的得到共享成员变量的变化。而 volatile
关键字就是提示 VM :对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互。
使用技巧:在两个或者更多的线程访问的成员变量上使用 volatile 。当要访问的变量已在 synchronized 代码块中,或者为常量时,不必使用。
线程为了提高效率,将某成员变量(如A)拷贝了一份(如B),线程中对A的访问其实访问的是B。只在某些动作时才进行A和B的同步,因此存在A和B不一致
的情况。volatile就是用来避免这种情况的。
volatile告诉jvm,它所修饰的变量不保留拷贝,直接访问主内存中的(读操作多时使用较好;线程间需要通信,本条做不到)
Volatile 变量具有 synchronized 的可见性特性,但是不具备原子特性。这就是说线程能够自动发现 volatile
变量的最新值。Volatile
变量可用于提供线程安全,但是只能应用于非常有限的一组用例:多个变量之间或者某个变量的当前值与修改后值
之间没有约束。
您只能在有限的一些情形下使用 volatile 变量替代锁。要使 volatile 变量提供理想的线程安全,必须同时满足下面两个条件:
对变量的写操作不依赖于当前值;该变量没有包含在具有其他变量的不变式中。
sleep() vs wait()
sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,把执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。
wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。
(如果变量被声明为volatile,在每次访问时都会和主存一致;如果变量在同步方法或者同步块中被访问,当在方法或者块的入口处获得锁以及方法或者块退出时释放锁时变量被同步。)
❹ java中 synchronized同步处理后 为什么只有一个线程在运行
java中
synchronized同步处理后,代表该线程是同步的,即多线程访问时,无法同时有两个或以上线程进行访问。具体的原理是,当第一个线程进入该同步代码块之后,会暂时获得同步块的锁,当第二个线程进入时,由于第一个线程并未结束,同步代码块的锁没有释放,所以第二个线程进不来,达到只有一个线程在运行的目的。synchronized同步处理通常用于封装需要共享的可改变的数据,为了让数据更安全所使用的技术。
❺ Java 线程同步几种方式
(1)同步来方法:
即有synchronized关键字修饰的自方法。 由于java的每个对象都有一个内置锁,当用此关键字修饰方法时,内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。
(2)同步代码块
即有synchronized关键字修饰的语句块。被该关键字修饰的语句块会自动被加上内置锁,从而实现同步
(3)使用特殊域变量(Volatile)实现线程同步
a.volatile关键字为域变量的访问提供了一种免锁机制
b.使用volatile修饰域相当于告诉虚拟机该域可能会被其他线程更新
c.因此每次使用该域就要重新计算,而不是使用寄存器中的值
d.volatile不会提供任何原子操作,它也不能用来修饰final类型的变量
(4)使用重入锁实现线程同步
在JavaSE5.0中新增了一个java.util.concurrent包来支持同步。ReentrantLock类是可重入、互斥、实现了Lock接口的锁, 它与使用synchronized方法和快具有相同的基本行为和语义,并且扩展了其能力。
(5)使用局部变量实现线程同步
❻ java 线程同步中synchronized关键字
一个对象的方法被线程调用的时候这个对象的其他方法被其他线程调用,这里面完全没有关系好吧
调用这个对象的锁定的方法为什么会锁定其他方法呢
你想问的是一个方法被多个线程调用的问题吧,有可能会存在死锁的情况
❼ java同步关键字有哪些
每一个对象都有来一把独占锁。自独占锁只限制线程对它的同步方法的访问,对非同步方法,独占锁没有意义。
synchronized是java中解决同步问题的一个方法。synchronized可以用来修饰方法,这样的方法就是同步方法。一个对象里可以有任意多个同步方法。任意时间里只能有一个线程访问这些同步方法。例如,现成T1在访问同步方法M1,此时还有一个同步方法M2此时无人访问,但是由于已经有一个线程正在访问这个对象的同步方法M1,所以试图访问M2的线程将被阻塞。直到T1对M1的访问结束。
可见同步方法有在一个同步方法运行期内保证只有一个线程能够进入。一旦方法结束,里面的线程就会失去对该对象的独占权。
synchronized语句块,可以指定要获得哪个对象的独占权,一旦获得,在语块执行过程中,线程会始终掌握该对象的独占权。此时,它可以连续访问多个该对象的同步方法。在整个过程中,独占权都牢牢掌握在该线程手中,其它线程没有任何机会。而如果没有同步语句块,则如果连续访问某个对象的同步方法,则在前一个方法返回,到下一个方法调用的间隙内,其他线程有机会抢先获得该对象的独占权。
❽ java中线程同步的几种方法
线程同步主要有以下种方法(示例中是实现计数的功能):
1、同步方法,即使用synchronized关键字修饰方法,例如:
publicsynchronizedvoidadd(intc){...}
2、同步代码块,即有synchronized关键字修饰的语句块,例如:
publicvoidaddAndGet(intc){
synchronized(this){
count+=c;
}
}
3、使用特殊域变量(volatile)实现线程同步,该方法不能保证绝对的同步。
例如:privatevolatileintcount=0;
4、使用锁实现线程同步,例如:
privateLocklock=newReentrantLock();
publicvoidadd(intc){
lock.lock();//上锁
try{
count+=c;
}finally{
lock.unlock();//解锁
}
}
5、使用原子变量实现线程同步,在java的util.concurrent.atomic包中提供了创建了原子类型变量的工具类,例如:
privateAtomicIntegercount=newAtomicInteger(1);
publicvoidadd(intc){
count.addAndGet(c);
}
6、使用局部变量实现线程同步,如果使用ThreadLocal管理变量,则每一个使用该变量的线程都获得该变量的副本, 副本之间相互独立,这样每一个线程都可以随意修改自己的变量副本,而不会对其他线程产生影响。
ThreadLocal 类的常用方法
new ThreadLocal<T>() : 创建一个线程本地变量
get() : 返回此线程局部变量的当前线程副本中的值
initialValue() : 返回此线程局部变量的当前线程的"初始值"
set(T value) : 将此线程局部变量的当前线程副本中的值设置为value
示例代码:
privatestaticThreadLocal<Integer>count=newThreadLocal<Integer>(){
@Override
protectedIntegerinitialValue(){
return1;
}
};
publicvoidadd(intc){
count.set(count.get()+c);
}
7、使用阻塞队列实现,例如LinkedBlockingQueue,具体使用可网络LinkedBlockingQueue的用法或查看java文档。
❾ JAVA 中 同步方法的关键字,为什么不推荐用 stop()和 suspend()
stop这个方法将终止所有未结束的方法,包括run方法。当一个线程停止时候,他会立即释放所有他锁住对象上的锁。这会导致对象处于不一致的状态。假如一个方法在将钱从一个账户转移到另一个账户的过程中,在取款之后存款之前就停止了。那么现在银行对象就被破坏了。因为锁已经被释放了。当线程想终止另一个线程的时候,它无法知道何时调用stop是安全的,何时会导致对象被破坏。所以这个方法被弃用了。你应该中断一个线程而不是停止他。
suspend不会破坏对象。但是,如果你用一个suspend挂起一个有锁的线程,那么在锁恢复之前将不会被释放。如果调用suspend的方法线程试图取得相同的锁,程序就会死锁。