接下来我将详细讲解“详谈Java多线程的几个常用关键字”。
一、Java多线程的几个常用关键字
Java中的多线程是通过Thread
类及Runnable
接口来实现的。在Java多线程中,有几个常用关键字需要熟知,如下所示:
-
synchronized
:用于实现同步,防止并发访问共享数据发生错误,并且保证了多线程的协调运行。 -
volatile
:用于保证可见性和禁止指令重排。 -
wait
、notify
、notifyAll
:用于实现线程之间的协作。
下面我们详细介绍一下这几个关键字及其使用场景。
二、synchronized关键字
synchronized
关键字是Java中实现同步的一种方式。它可以修饰方法或代码块,在多线程中保证线程之间的同步执行,从而防止数据的竞争和错误。
1. synchronized方法
在Java中,使用synchronized
关键字修饰的方法称为synchronized
方法。当某个线程调用一个synchronized
方法时,会自动获取该对象的锁,直到该方法执行完毕后才会自动释放该对象锁。
示例代码:
public class SynchronizedDemo {
public synchronized void synchronizedMethod() {
// do something...
}
}
上面的示例中,我们使用synchronized
关键字修饰了synchronizedMethod
方法,从而保证该方法在多线程执行时的同步访问。
2. synchronized代码块
synchronized
关键字还可以用于修饰代码块,使用synchronized
代码块可以精确控制多个线程之间的同步访问。
示例代码:
public class SynchronizedDemo {
public void synchronizedBlock() {
synchronized (this) {
// do something...
}
}
}
上面的示例中,我们使用synchronized
关键字修饰了代码块,从而控制某段代码在多线程间的同步访问。
三、volatile关键字
volatile
关键字与synchronized
关键字一样,都是为了多线程的正确执行而设计的。使用volatile
关键字可以保证可见性和禁止指令重排。
1. 保证可见性
Java内存模型中的可见性是指,当一个线程修改了共享变量的值时,其他线程能够立即看到修改后的值。使用volatile
关键字修饰的变量,可以使该变量的修改对其他线程立即可见。
示例代码:
public class VolatileDemo {
private volatile int value = 0;
public void setValue(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public static void main(String[] args) {
VolatileDemo demo = new VolatileDemo();
new Thread(() -> {
demo.setValue(10);
}).start();
new Thread(() -> {
System.out.println(demo.getValue());
}).start();
}
}
上面的示例中,我们使用volatile
关键字修饰了value
变量,从而实现了多个线程之间的可见性。
2. 禁止指令重排
在Java编译器中,为了优化代码运行速度,可能会进行指令重排,即改变指令的顺序,但并不会改变程序的运行结果。但在多线程中,指令重排会导致程序出现难以预料的错误。因此,为了保证多线程执行的正确性,我们需要使用volatile
关键字来禁止指令重排。
示例代码:
public class VolatileDemo {
private static volatile VolatileDemo instance;
public static VolatileDemo getInstance() {
if (instance == null) {
synchronized (VolatileDemo.class) {
if (instance == null) {
instance = new VolatileDemo();
}
}
}
return instance;
}
}
上面的示例中,我们使用了volatile
关键字来修饰单例模式中的instance
变量,从而保证了该变量的可见性和禁止指令重排。
四、wait、notify、notifyAll关键字
在Java中,我们可以使用wait
、notify
、notifyAll
关键字来实现线程间的协作,从而更好地实现多线程的协调运行。
1. wait关键字
wait
关键字用于使当前线程等待,直到其他线程调用该对象的notify
或notifyAll
方法,唤醒当前线程继续执行。
示例代码:
public class WaitNotifyDemo {
private boolean flag = true;
public synchronized void printA() {
while (!flag) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("A");
flag = false;
notifyAll();
}
public synchronized void printB() {
while (flag) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("B");
flag = true;
notifyAll();
}
public static void main(String[] args) {
WaitNotifyDemo demo = new WaitNotifyDemo();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
demo.printA();
}
}).start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
demo.printB();
}
}).start();
}
}
上面的示例中,我们使用了wait
和notifyAll
关键字来实现了线程之间的协作,当打印完"A"后,会唤醒其他线程去执行。
2. notify关键字
notify
关键字唤醒一个正在等待当前对象锁的线程。如果有多个线程正在等待该对象锁,则只有一个线程会被唤醒。
示例代码:
public class WaitNotifyDemo {
private Object lock = new Object();
public void print() {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " 获取到锁");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.notify();
System.out.println(Thread.currentThread().getName() + " 唤醒等待线程");
}
}
public static void main(String[] args) {
WaitNotifyDemo demo = new WaitNotifyDemo();
new Thread(() -> {
synchronized (demo.lock) {
try {
System.out.println(Thread.currentThread().getName() + " 等待获取锁");
demo.lock.wait();
System.out.println(Thread.currentThread().getName() + " 获取到锁");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(() -> {
demo.print();
}).start();
}
}
上面的示例中,我们使用了wait
和notify
关键字来实现了线程之间的协作,当线程1等待获取锁时,线程2获取到锁并执行完毕,然后唤醒线程1继续执行。
3. notifyAll关键字
notifyAll
关键字唤醒所有正在等待当前对象锁的线程,让它们去竞争获取对象锁。
示例代码:
public class WaitNotifyDemo {
private Object lock = new Object();
public void print() {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " 获取到锁");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.notifyAll();
System.out.println(Thread.currentThread().getName() + " 唤醒等待线程");
}
}
public static void main(String[] args) {
WaitNotifyDemo demo = new WaitNotifyDemo();
for (int i = 0; i < 5; i++) {
new Thread(() -> {
synchronized (demo.lock) {
try {
System.out.println(Thread.currentThread().getName() + " 等待获取锁");
demo.lock.wait();
System.out.println(Thread.currentThread().getName() + " 获取到锁");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
new Thread(() -> {
demo.print();
}).start();
}
}
上面的示例中,我们使用了wait
和notifyAll
关键字来实现了线程之间的协作,当线程1等待获取锁时,线程2获取到锁并执行完毕,然后唤醒所有等待线程去竞争获取对象锁。
五、总结
Java中的多线程是一种非常重要的技术,其中有几个常用关键字需要熟知,如synchronized
、volatile
、wait
、notify
、notifyAll
等。使用这些关键字可以使多线程之间的协调运行更加平稳和有效。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详谈Java多线程的几个常用关键字 - Python技术站