对比下面几种方式的输出:
package com.thread.test;
public class ThreadTest1 implements Runnable {
static ThreadTest1 test = new ThreadTest1();
// volatile只能保证线程之间数据可见,但并不保证线程安全
static volatile int i = 0;
public static void increase() {
i++;
}
@Override
public void run() {
for (int i = 0; i < 1000000; i++) {
increase();
}
}
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(test);
Thread thread2 = new Thread(test);
// 测试1
thread1.start();
thread2.start();
thread1.join();
thread2.join();
// 测试2
// thread1.start();
// thread2.start();
// 测试3
// thread1.start();
// thread1.join();
// thread2.start();
// thread2.join();
System.err.println(i);
}
}
package com.thread.test;
public class ThreadTest2 implements Runnable {
// volatile只能保证线程之间数据可见,但并不保证线程安全
static volatile int i = 0;
// 此方法不使用静态方法时
public synchronized void increase() {
i++;
}
@Override
public void run() {
for (int i = 0; i < 1000000; i++) {
increase();
}
}
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new ThreadTest2());
Thread thread2 = new Thread(new ThreadTest2());
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.err.println(i);
}
}
上面的代码测试中,虽然increase使用了锁,但是在 20、21行使用的Runnable实例不是同一个,所以线程thread1和线程thread2只关心各自的锁,也就是说,这两个线程使用的不是同一把锁,所以即使increase使用了synchronized 关键字,输出结果仍然不对。
针对这种情况,解决方案是将increase修改为static
package com.thread.test;
public class ThreadTest2 implements Runnable {
// volatile只能保证线程之间数据可见,但并不保证线程安全
static volatile int i = 0;
// 此方法使用静态方法时
public static synchronized void increase() {
i++;
}
@Override
public void run() {
for (int i = 0; i < 1000000; i++) {
increase();
}
}
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new ThreadTest2());
Thread thread2 = new Thread(new ThreadTest2());
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.err.println(i);
}
}