
本文主要介绍Java多线程中的同步,即如何用Java语言编写线程安全程序,以及如何解决Java语言中与线程安全无关的问题. 是的,它是同步的.
一般来说,如何解决线程安全问题?
基本上,所有并发模式在解决线程安全问题时都使用“对关键资源的串行访问”解决方案,即一次只能有一个线程可以访问关键资源,也称为同步互斥锁.
通常来说,是在访问关键资源的代码前添加一个锁. 当访问关键资源时,将释放锁,以允许其他线程继续访问.
在Java中,有两种方法可以实现同步互斥访问: synced和Lock. 本文主要讨论同步的使用,稍后将介绍Lock的使用.
1. 简介
同步,我们称为锁定,主要用于锁定方法和代码块. 当一种方法或代码块使用同步时,则最多有一个线程在同一时间执行代码. 当多个线程访问同一对象的锁方法/代码块时,只有一个线程正在同时执行,其余线程必须等待当前线程执行后才能执行代码段. 但是,其余线程可以访问对象中的非锁定代码块.
同步化主要包括两种方法: 同步化方法,同步块化.
2. 同步方法
通过在方法声明中添加synced关键字来声明同步方法. 如:
public synchronized void getResult();
同步方法控制对类成员变量的访问. 如何避免对类成员变量的访问控制?我们知道该方法使用synced关键字表示该方法已被锁定. 当任何线程访问更改的方法时,它必须确定该方法中是否还有其他“独占”线程. 每个类实例都对应一个锁,每个同步方法都必须在执行该方法之前调用该方法的类实例的锁,否则将阻塞所属线程,并且一旦执行该方法,该锁就被独占,直到返回从方法. 释放后,被阻止的线程可以获得锁.
实际上,同步方法有缺陷. 如果我们将大型方法声明为同步方法,则将大大影响效率. 如果多个线程正在访问同步方法,则只有一个线程在同一时间执行该方法,而其他线程必须等待,但是如果该方法未使用同步,则所有线程都可以同时执行它,从而减少了执行时间. 总时间. 因此,如果我们知道一个方法不会被多个线程执行,或者没有资源共享的问题,那么我们就不需要使用synced关键字. 但是,如果您必须使用synced关键字,那么我们可以用synced代码块替换synced方法.
3. 同步块
同步代码块与同步方法具有相同的作用,不同之处在于它使关键部分尽可能短. 换句话说: 它仅保护所需的共享数据,而剩下的长代码块则保留此操作. 语法如下:

synchronized(object) {
//允许访问控制的代码
}
如果我们需要以这种方式使用synced关键字,则必须将对象引用作为参数传递,通常是我们经常以此为参数.
synchronized (this) {
//允许访问控制的代码
}
4. 使用同步
同步代码块,修改后的代码成为同步语句块,其范围是调用此代码块的对象. 当使用synced关键字时,我们可以尽可能缩小代码段的范围. 将同步添加到段时,请勿将同步添加到整个方法. 这称为减小锁的粒度并提高代码的并发性.
同步方法,修改后的方法成为同步方法线程安全问题代码,其作用范围是整个方法,而功能对象是调用此方法的对象.
同步静态方法,修改静态静态方法,其作用域是整个静态方法,对象的作用是此类的所有对象.
Synchronized类,其作用域为sync(className.class),该类用Synchronized后面的括号括起来,作用对象是此类的所有对象.
synchronized(),()是锁定的对象,synced(this)仅锁定对象本身,不会锁定由相同类的不同对象调用的sync方法,并且sync(className.class)实现了该功能对于全局锁,此类调用此方法的所有对象均受该锁的影响,此外()还可以添加特定对象以实现对特定对象的锁定.
5. 同步注意事项
当两个并发线程访问同一对象中的同步代码块时,只能同时执行一个线程,而另一个线程则被阻塞. 在执行代码之前,必须等待当前线程执行此代码块. 片. 这两个线程是互斥的,因为当前对象在执行同步代码块时被锁定. 只有执行代码块后,才能释放对象锁定,并且下一个线程可以执行并锁定对象.
当一个线程访问对象的同步(此)同步代码块时,另一个线程仍可以访问对象中的非同步(此)同步代码块. (两个线程使用相同的对象)
当线程访问对象的同步代码块时,其他线程对该对象中所有其他同步代码块的访问将被阻止(与上述相同线程安全问题代码,两个线程使用同一对象).
以下是通过代码实现的:
1)当两个并发线程访问同一对象中的此同步(此)同步代码块时,一次只能执行一个线程. 另一个线程必须等待当前线程执行代码块,然后才能执行代码块.


public class Thread1 implements Runnable {
public void run() {
synchronized(this) {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " synchronized loop " + i);
}
}
}
public static void main(String[] args) {
Thread1 t1 = new Thread1();
Thread ta = new Thread(t1, "A");
Thread tb = new Thread(t1, "B");
ta.start();
tb.start();
}
}

输出结果:

A synchronized loop 0 A synchronized loop 1 A synchronized loop 2 A synchronized loop 3 A synchronized loop 4 B synchronized loop 0 B synchronized loop 1 B synchronized loop 2 B synchronized loop 3 B synchronized loop 4

2)但是,当一个线程访问对象的已同步代码块时,另一个线程仍可以访问对象中未同步的代码块.

public class Thread2 {
public void m4t1() {
synchronized(this) {
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
}
}
}
public void m4t2() {
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
}
}
public static void main(String[] args) {
final Thread2 myt2 = new Thread2();
Thread t1 = new Thread( new Runnable() { public void run() { myt2.m4t1(); } }, "t1" );
Thread t2 = new Thread( new Runnable() { public void run() { myt2.m4t2(); } }, "t2" );
t1.start();
t2.start();
}
}

输出结果:

t1 : 4 t2 : 4 t1 : 3 t2 : 3 t1 : 2 t2 : 2 t1 : 1 t2 : 1 t1 : 0 t2 : 0


3)特别是,当一个线程访问一个对象的同步代码块时,其他线程对该对象中所有其他同步代码块的访问将被阻止.

//修改Thread2.m4t2()方法:
public void m4t2() {
synchronized(this) {
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
}
}
}

输出结果:

t1 : 4 t1 : 3 t1 : 2 t1 : 1 t1 : 0 t2 : 4 t2 : 3 t2 : 2 t2 : 1 t2 : 0

4)第三个示例也适用于其他同步代码块. 换句话说,当线程访问对象的同步(此)同步代码块时,它将获取对象的对象锁. 结果,其他线程对对象对象的所有同步代码部分的访问都被暂时阻止.

//修改Thread2.m4t2()方法如下:
public synchronized void m4t2() {
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
}
}
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-269774-1.html