synchronized关键字的作用是什么,最准确描述synchronized关键字
Synchronized关键字是java并发编程中常用的同步锁,用于锁定方法或代码块。锁定代码块时,可以是synchronized(this){},synchronized(Object){},synchronized (class){}。
如何解决写爬虫IP受阻的问题?立即使用。
当锁定的内容结束或在执行过程中抛出异常时,锁将被自动释放。
如果要手动释放锁,需要调用被锁定对象的wait()方法来释放锁并使其处于等待状态,切换到其他线程。notify()方法只唤醒另一个调用对象wait()方法的线程,但不会释放锁,选择顺序不受代码控制,由虚拟机实现。
因此,对象的wait()、notify()和notifyAll()方法只能与synchronized关键字一起使用,以完成线程间的调度。
其中锁定方法相当于同步(this){方法的所有代码作为代码块},如下所示:
公共同步void测试(){
.
}相当于
公共无效测试(){
同步(这){
.
}
}上面的例子锁定了这个类的对象。如果锁定的方法是静态方法,我们知道静态方法属于类而不是对象。因此,同步修改的静态方法锁定该类的所有对象,也就是说,即使是两个实例对象,只要都是该类,也会被锁定。
公共同步静态void测试(){
.
}相当于
公共静态void测试(){
同步(类。类){
.
}
}不管是锁方法还是代码块,不管锁代码块时引用的对象是什么,只要记住一个原则就一目了然了,就是引用对象相同时,同步锁才会起作用,否则锁不会互斥,可以并发执行。
Synchronized(this)表示当当前类的对象实例相同时锁起作用,synchronized(Object)表示当对象对象相同时锁起作用,synchronized (class class)表示当它们都是这个类时锁起作用。
举个简单的例子:
公共类TestController {
公共类任务实现Runnable{
私有字符串str
任务(字符串)
this.str=str
}
@覆盖
公共无效运行(){
同步(字符串){
尝试{
thread . sleep(3000 l);
} catch (InterruptedException e) {
e . printstacktrace();
}
system . out . println(str);
}
}
}
公共静态void main(String[] args)引发InterruptedException {
test controller test controller=new test controller();
Thread thread1=新线程(test controller . new Task( 1 ));
Thread thread2=新线程(test controller . new Task( 1 ));
thread 1 . start();
thread 2 . start();
}
}在上面的代码中,引用对象str是‘1’。在java中,如果字符串String由this.str=1 赋值,则等效于str=String.valueOf(1 )。如果字符串 1 之前已经初始化过,它会直接取前一个,所以是同一个对象。根据上面介绍的原理,锁会起作用,所以结果是3秒后输出1,3秒后再输出1。
如果将thread2改为
Thread thread2=新线程(test controller . new Task( 2 ));此时参考对象一个是 1 ,一个是 2 ,不是同一个对象,所以锁不会互斥,不会起作用,所以结果是3秒后1和2几乎同时输出。
以上都是多线程同时调用同一个方法。如果调用不同的方法呢?
公共类测试{
公共同步void m1(){
System.out.println(m1正在运行.);
尝试{
thread . sleep(3000 l);
} catch (InterruptedException e) {
e . printstacktrace();
}
system . out . println(“m1 end”);
}
公共同步void m2(){
System.out.println(m2正在运行.);
system . out . println(“m2 end”);
}
公共静态void main(String[] args) {
测试Test=new Test();
新线程(新Runnable() {
@覆盖
公共无效运行(){
test . m1();
}
}).start();
新线程(新Runnable() {
@覆盖
公共无效运行(){
test . m2();
}
}).start();
}
}上面代码的输出结果是:
m1运行.
//3秒钟后
m1端
m2运行.
M2在上面说过,synchronized modification相当于synchronized(this){将方法的所有代码作为一个代码块},this代表成为一个对象。也就是说,第一个线程获得测试对象的锁。因为所有的对象都是相同的测试,所以第二个线程不能获得锁并被阻塞。
将上述示例转换为以下内容:
私有字符串str= 1
公共void m1(){
同步(字符串){
System.out.println(m1正在运行.);
尝试{
thread . sleep(3000 l);
} catch (InterruptedException e) {
e . printstacktrace();
}
system . out . println(“m1 end”);
}
}
公共void m2(){
同步(字符串){
System.out.println(m2正在运行.);
system . out . println(“m2 end”);
}
}第一个线程调用m1()时,获取对象str的锁,第二个线程调用m2()时,也需要获取对象str的锁。而且因为是同一个测试对象,所以两个str是同一个对象,所以第二个线程会因为拿不到锁而被阻塞。输出结果与前面的示例相同。
如果上面的例子修改如下:
公共类M1 {
public void m(String str){
同步(字符串){
system . out . println( m1 running );
尝试{
thread . sleep(3000 l);
} catch (InterruptedException e) {
e . printstacktrace();
}
system . out . println(“m1 end”);
}
}
}
公共类M2 {
public void m(String str){
同步(字符串){
system . out . println( m2 runing );
system . out . println(“m2 end”);
}
}
}
公共类测试{
公共静态void main(String[] args) {
String str= 1
新线程(新Runnable() {
@覆盖
公共无效运行(){
新M1()。m(str);
}
}).start();
新线程(新Runnable() {
@覆盖
公共无效运行(){
新M2()。m(str);
}
}).start();
}
}这个调用的方法在两个类中,但是结果和前面两个例子一样,因为传入的都是锁定的str对象,同一个对象只有一个锁。第一个线程拿,第二个线程只能等。
总结:
A.无论synchronized关键字添加到方法还是对象,如果它作用的对象是非静态的,那么它获取的锁就是对象;如果同步的对象是一个静态方法或类,它获得的锁是一对类,并且该类的所有对象都有相同的锁。
B.每个对象只有一个与之关联的锁,获得这个锁的人可以运行它所控制的代码。
C.实现同步需要耗费大量的系统开销,甚至可能造成死锁,所以尽量避免不必要的同步控制。以上是同步关键词使用的详细内容。请多关注我们的其他相关文章!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。