synchronized
关键字是一种同步机制,用于控制多个线程访问共享资源的方式。这是防止线程干扰和内存一致性错误的一种方法。synchronized
可以用于方法或代码块。
当一个线程调用 synchronizedMethod
时,其他线程必须等待,直到该线程执行完毕才能访问这个方法。
public class Counter {
private int count = 0;
// 同步方法
public synchronized void increment() {
count++;
}
public int getCount() {
return count;
}
}
public class Main {
public static void main(String[] args) {
Counter counter = new Counter();
// 创建两个线程,同时增加计数器的值
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
thread1.start();
thread2.start();
try {
// 等待两个线程执行完毕
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 输出最终计数器的值
System.out.println("最终计数器的值:" + counter.getCount());
}
}
Counter
类:private int count=0;
私有成员变量,用于存储计数值。这个计数器是共享资源,多个线程将会同时访问它。
public synchronized void increment()
:这是一个同步方法,用于增加计数值。由于它被标记为 synchronized
,因此只有一个线程可以同时访问这个方法。当一个线程调用 increment
方法时,其他线程必须等待,直到该线程执行完毕。这确保了对计数器的递增操作是线程安全的。
public int getCount()
:这是一个普通的非同步方法,用于获取计数值。由于没有使用 synchronized
关键字,所以多个线程可以同时访问它。
在 main
方法中,首先创建了一个 Counter
对象 counter
,用于存储计数值。
然后,创建了两个线程 thread1
和 thread2
,它们将同时执行 counter.increment()
方法来增加计数器的值。每个线程循环执行 1000
次递增操作。
使用 thread1.start()
和 thread2.start()
启动这两个线程。
使用 thread1.join()
和 thread2.join()
等待这两个线程执行完毕。这样确保了在输出最终计数值之前,两个线程都已经完成了它们的工作。
最后,使用 counter.getCount()
获取最终的计数器值,并将其打印到屏幕上。
public class SynchronizedExample {
// 私有成员变量,用于存储计数值
private int count = 0;
// 同步方法,用于增加计数值
public synchronized void increment() {
count++;
}
// 同步方法,用于获取计数值
public synchronized int getCount() {
return count;
}
}
public class SynchronizedExampleTest {
public static void main(String[] args) {
// 创建 SynchronizedExample 实例
SynchronizedExample example = new SynchronizedExample();
// 创建多个线程执行增加计数的操作
Thread[] incrementThreads = new Thread[6];
for (int i = 0; i < incrementThreads.length; i++) {
incrementThreads[i] = new Thread(() -> {
for (int j = 0; j < 1000; j++) {
example.increment();
}
});
}
// 创建多个线程执行获取计数的操作
Thread[] getCountThreads = new Thread[6];
for (int i = 0; i < getCountThreads.length; i++) {
getCountThreads[i] = new Thread(() -> {
int count = example.getCount();
System.out.println("Count: " + count);
});
}
// 启动所有增加计数的线程
for (Thread thread : incrementThreads) {
thread.start();
}
// 启动所有获取计数的线程
for (Thread thread : getCountThreads) {
thread.start();
}
// 等待所有线程完成
try {
for (Thread thread : incrementThreads) {
thread.join();
}
for (Thread thread : getCountThreads) {
thread.join();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
// 输出最终的计数值
int finalCount = example.getCount();
System.out.println("Final Count: " + finalCount);
}
}
SynchronizedExample
类count
:这是一个私有成员变量,用于存储计数值。increment()
方法:这是一个同步方法,用于安全地增加count
的值。由于这个方法是synchronized
的,当一个线程在执行这个方法时,其他线程必须等待,直到该方法执行完毕。getCount()
方法:这也是一个同步方法,用于安全地获取count
的当前值。同样,当一个线程执行这个方法时,其他线程不能同时执行任何其他同步方法(比如increment
)。SynchronizedExampleTest
类main
方法中,首先创建了一个SynchronizedExample
的实例。increment
方法,另外6个用于执行getCount
方法。increment
的线程都会将count
增加1000次。getCount
的线程都会获取并打印当前的count
值。thread.start()
启动所有线程。thread.join()
等待所有线程完成。这确保了在输出最终count
值之前,所有增加和获取计数的操作都已完成。使用同步代码块可以保护共享资源
public class SynchronizedBlockExample {
public static void main(String[] args) {
// 创建共享资源对象
SharedResource sharedResource = new SharedResource();
// 创建线程1,用于递增计数器
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
sharedResource.increment();
}
});
// 创建线程2,用于递增计数器
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
sharedResource.increment();
}
});
// 启动线程1和线程2
thread1.start();
thread2.start();
try {
// 等待线程1和线程2执行完毕
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 获取最终计数器值并输出
int finalCount = sharedResource.getCount();
System.out.println("最终计数值: " + finalCount);
}
}
class SharedResource {
private int count = 0;
private Object lock = new Object(); // 创建一个锁对象
public void increment() {
// 使用锁对象创建同步代码块,确保线程安全
synchronized (lock) {
count++;
}
}
public int getCount() {
// 使用锁对象创建同步代码块,确保线程安全
synchronized (lock) {
return count;
}
}
}
创建共享资源对象:创建了一个 SharedResource
的实例,该实例包含一个计数器和一个锁对象。
创建线程1和线程2:创建了两个线程,它们分别执行递增计数器的操作。
启动线程1和线程2:通过调用 start
方法启动线程,使它们开始执行递增操作。
等待线程1和线程2执行完毕:使用 join
方法等待线程1和线程2执行完毕,以确保获取最终计数值时线程已经完成。
获取最终计数器值并输出:使用 getCount
方法获取最终的计数器值,然后将其输出到控制台。
使用锁对象创建同步代码块:在 increment
和 getCount
方法内部使用锁对象 lock
创建同步代码块,确保对计数器的递增和读取操作是线程安全的。只有一个线程可以同时持有 lock
锁,因此多线程不会同时访问计数器。这种同步机制确保了线程安全性。
synchronized
静态方法同步提供了一种简单的方式来确保线程安全,但过度使用同步可能会导致性能问题,因为只能有一个线程同时执行同步方法。因此,在设计中需要权衡线程安全性和性能之间的取舍,仅在需要确保线程安全的情况下使用synchronized
静态方法同步。
package three;
public class SynchronizedStaticMethodExample {
public static void main(String[] args) {
// 创建两个线程,分别访问静态同步方法
Thread thread1 = new Thread(() -> {
SharedResource.staticIncrement();
});
Thread thread2 = new Thread(() -> {
SharedResource.staticIncrement();
});
// 启动线程1和线程2
thread1.start();
thread2.start();
try {
// 等待线程1和线程2执行完毕
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 输出最终的计数值
int finalCount = SharedResource.getStaticCount();
System.out.println("最终静态计数值: " + finalCount);
}
}
class SharedResource {
private static int staticCount = 0;
// 静态同步方法,用于增加计数值
public static synchronized void staticIncrement() {
staticCount++;
}
// 静态同步方法,用于获取计数值
public static synchronized int getStaticCount() {
return staticCount;
}
}
创建两个线程:在 main
方法中,创建了两个线程 thread1
和 thread2
,它们将分别访问静态同步方法。
启动线程1和线程2:使用 thread1.start()
和 thread2.start()
启动这两个线程,使它们开始执行静态同步方法。
等待线程1和线程2执行完毕:使用 thread1.join()
和 thread2.join()
等待线程1和线程2执行完毕,以确保获取最终的计数器值时线程已经完成。
输出最终的计数值:使用 SharedResource.getStaticCount()
获取最终的静态计数器值,并将其输出到控制台。
静态同步方法:SharedResource
类中包含两个静态同步方法 staticIncrement
和 getStaticCount
,它们分别用于递增计数器和获取计数器值。由于这两个方法都被标记为 synchronized
,只有一个线程可以同时访问它们,从而确保了对静态计数器的递增和读取操作是线程安全的。
synchronized
关键字用于控制多个线程对共享资源的访问,以确保线程安全。
同步方法:通过将方法标记为 synchronized
,可以确保在同一时刻只有一个线程可以执行该方法,其他线程必须等待。
同步代码块:通过使用同步代码块,可以在特定的代码块内部使用锁对象来确保对共享资源的安全访问。
静态方法同步:通过将静态方法标记为 synchronized
,可以确保在同一时刻只有一个线程可以执行该静态方法,用于保护静态数据成员的访问。
使用同步可以防止线程干扰、内存一致性错误、竞态条件等多线程问题。
注意,过度使用同步可能会导致性能问题,因此需要在线程安全性和性能之间进行权衡。