为什么我的同步方法不能正常工作?
Why my synchronized method not working properly?
我有这个打印计数器的同步方法,我有 4 个线程,所以我期望计数器的最终值为 400000,因为我的计数器是一个静态变量。
但每次我 运行 我的代码,它都会给我不同的计数器值。
以下是我的代码:
class MyThread implements Runnable{
private static int counter=1;
@Override
public void run() {
try {
this.syncMethod();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void syncMethod() throws InterruptedException{
for(int i=0;i<100000;i++){
System.out.println(Thread.currentThread().getName()+" : "+counter++);
}
}
}
public class MyController {
public static void main(String[] args) throws InterruptedException {
Runnable r1=new MyThread();
Runnable r2=new MyThread();
Runnable r3=new MyThread();
Runnable r4=new MyThread();
Thread t1;
Thread t2;
Thread t3;
Thread t4;
t1=new Thread(r1,"Thread 1");
t2=new Thread(r2,"Thread 2");
t3=new Thread(r3,"Thread 3");
t4=new Thread(r4,"Thread 4");
t2.start();
t1.start();
t3.start();
t4.start();
}
}
变量是static
,但是你synchronized
的方法不是static
。这意味着它将获取当前实例上的监视器,并且每个线程都有不同的当前实例。
一个简单的解决方案是将 syncMethod
方法也设为 static
;在这种情况下,它将锁定由 MyThread
class:
的所有实例共享的监视器
public static synchronized void syncMethod()
Erwin Bolwidt 的回答可以解决您的问题。作为在 多个 线程中安全地增加静态共享 计数器 的另一种方法,您可以转向 AtomicLong。
定义为:
private static AtomicLong counter = new AtomicLong();
增加为:
counter.getAndIncrement();
最后得到结果:
counter.get();
非静态方法中的 synchronized 关键字意味着完全同步我这个方法:这两个代码是严格等效的:
public synchronised void dojob(){
//the job to do
}
等
public void dojob(){
synchronised (this){
//the job to do
}
}
在您的情况下,您的同步方法在不同的对象(t1、t2、t3 和 t4)上同步,因此不会相互阻塞。最好的解决方案是你的线程将使用一个公共对象来相互同步。另一点总是最好让它的线程返回来做这个调用 join 这里是一个代码来做你想用这 2 个修复
class MyThread implements Runnable {
public static class JobDoer {
public synchronized void syncMethod() throws InterruptedException {
for (int i = 0; i < 100000; i++) {
System.out.println(Thread.currentThread().getName() + " : " + counter++);
}
}
}
private static int counter = 1;
public MyThread(JobDoer doer) {
this.doer = doer;
}
private JobDoer doer;
@Override
public void run() {
try {
doer.syncMethod();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
JobDoer doer = new JobDoer();
Thread t1 = new Thread(new MyThread(doer), "Thread 1");
Thread t2 = new Thread(new MyThread(doer), "Thread 2");
Thread t3 = new Thread(new MyThread(doer), "Thread 3");
Thread t4 = new Thread(new MyThread(doer), "Thread 4");
t2.start();
t1.start();
t3.start();
t4.start();
t1.join();
t2.join();
t3.join();
t4.join();
}
}
我有这个打印计数器的同步方法,我有 4 个线程,所以我期望计数器的最终值为 400000,因为我的计数器是一个静态变量。
但每次我 运行 我的代码,它都会给我不同的计数器值。
以下是我的代码:
class MyThread implements Runnable{
private static int counter=1;
@Override
public void run() {
try {
this.syncMethod();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void syncMethod() throws InterruptedException{
for(int i=0;i<100000;i++){
System.out.println(Thread.currentThread().getName()+" : "+counter++);
}
}
}
public class MyController {
public static void main(String[] args) throws InterruptedException {
Runnable r1=new MyThread();
Runnable r2=new MyThread();
Runnable r3=new MyThread();
Runnable r4=new MyThread();
Thread t1;
Thread t2;
Thread t3;
Thread t4;
t1=new Thread(r1,"Thread 1");
t2=new Thread(r2,"Thread 2");
t3=new Thread(r3,"Thread 3");
t4=new Thread(r4,"Thread 4");
t2.start();
t1.start();
t3.start();
t4.start();
}
}
变量是static
,但是你synchronized
的方法不是static
。这意味着它将获取当前实例上的监视器,并且每个线程都有不同的当前实例。
一个简单的解决方案是将 syncMethod
方法也设为 static
;在这种情况下,它将锁定由 MyThread
class:
public static synchronized void syncMethod()
Erwin Bolwidt 的回答可以解决您的问题。作为在 多个 线程中安全地增加静态共享 计数器 的另一种方法,您可以转向 AtomicLong。
定义为:
private static AtomicLong counter = new AtomicLong();
增加为:
counter.getAndIncrement();
最后得到结果:
counter.get();
非静态方法中的 synchronized 关键字意味着完全同步我这个方法:这两个代码是严格等效的:
public synchronised void dojob(){
//the job to do
}
等
public void dojob(){
synchronised (this){
//the job to do
}
}
在您的情况下,您的同步方法在不同的对象(t1、t2、t3 和 t4)上同步,因此不会相互阻塞。最好的解决方案是你的线程将使用一个公共对象来相互同步。另一点总是最好让它的线程返回来做这个调用 join 这里是一个代码来做你想用这 2 个修复
class MyThread implements Runnable {
public static class JobDoer {
public synchronized void syncMethod() throws InterruptedException {
for (int i = 0; i < 100000; i++) {
System.out.println(Thread.currentThread().getName() + " : " + counter++);
}
}
}
private static int counter = 1;
public MyThread(JobDoer doer) {
this.doer = doer;
}
private JobDoer doer;
@Override
public void run() {
try {
doer.syncMethod();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
JobDoer doer = new JobDoer();
Thread t1 = new Thread(new MyThread(doer), "Thread 1");
Thread t2 = new Thread(new MyThread(doer), "Thread 2");
Thread t3 = new Thread(new MyThread(doer), "Thread 3");
Thread t4 = new Thread(new MyThread(doer), "Thread 4");
t2.start();
t1.start();
t3.start();
t4.start();
t1.join();
t2.join();
t3.join();
t4.join();
}
}