synchronized关键字主要要3中加锁的方式
– 指定加锁对象:对给定对象加锁,进入同步代码前要获得给定对象的锁。
– 直接作用于实例方法:相当于对当前实例加锁,进入同步代码前要获得当前实例的锁。
– 直接作用于静态方法:相当于对当前类加锁,进入同步代码前要获得当前类的锁。
- 指定加锁对象
指定对象加锁,必须确保加锁的对象是同一个
package cn.zengzehao.thread;
public class SynchronizedDemo implements Runnable{
static SynchronizedDemo instance = new SynchronizedDemo();
static int count=0;
@Override
public void run() {
for (int i = 0; i < 1000000; i++) {
synchronized (instance) {
count++;
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(instance);
Thread thread2 = new Thread(instance);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(count);
}
}
看一个错误的例子
public class SynchronizedDemo implements Runnable{
Object instance = new Object();
static int count=0;
@Override
public void run() {
for (int i = 0; i < 1000000; i++) {
synchronized (instance) {
count++;
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new SynchronizedDemo());
Thread thread2 = new Thread(new SynchronizedDemo());
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(count);
}
}
程序加锁的对象是实例变量,是不一样的,如果在声明instance前加上static,声明一个类变量,那程序加锁就是同一个对象。
程序经常也会用this,当前对象加锁,在使用this的时候也要保证用一个锁
package cn.zengzehao.thread;
public class SynchronizedDemo implements Runnable{
static int count=0;
@Override
public void run() {
for (int i = 0; i < 1000000; i++) {
synchronized (this) {
count++;
}
}
}
public static void main(String[] args) throws InterruptedException {
//正确的
SynchronizedDemo t = new SynchronizedDemo();
Thread thread1 = new Thread(t);
Thread thread2 = new Thread(t);
//错误的,因为new了两个对象,run()的this是不一样的
/*Thread thread1 = new Thread(new SynchronizedDemo());
Thread thread2 = new Thread(new SynchronizedDemo());*/
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(count);
}
}
还有一种比较常见的就是给当前类加锁,这种方式的话,不管是new多少个对象,都是同一个锁
public class SynchronizedDemo implements Runnable{
static int count=0;
@Override
public void run() {
for (int i = 0; i < 1000000; i++) {
synchronized (SynchronizedDemo.class) {
count++;
}
}
}
public static void main(String[] args) throws InterruptedException {
//正确的
/*SynchronizedDemo t = new SynchronizedDemo();
Thread thread1 = new Thread(t);
Thread thread2 = new Thread(t);*/
Thread thread1 = new Thread(new SynchronizedDemo());
Thread thread2 = new Thread(new SynchronizedDemo());
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(count);
}
}
- 给实例方法加锁
package cn.zengzehao.thread;
public class SynchronizedDemo2 implements Runnable{
static SynchronizedDemo2 instance = new SynchronizedDemo2();
static int count=0;
@Override
public void run() {
for (int i = 0; i < 100000000; i++) {
increase();
}
}
public synchronized void increase(){
count++;
}
public static void main(String[] args) throws InterruptedException{
Thread thread1 = new Thread(instance);
Thread thread2 = new Thread(instance);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(count);
}
}
- 给类方法加锁
package cn.zengzehao.thread;
public class SyschronizedDemo3 implements Runnable {
static int count=0;
@Override
public void run() {
for (int i = 0; i < 100000000; i++) {
increase();
}
}
public static synchronized void increase(){
count++;
}
public static void main(String[] args) throws InterruptedException{
Thread thread1 = new Thread(new SyschronizedDemo3());
Thread thread2 = new Thread(new SyschronizedDemo3());
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(count);
}
}
4.容易犯错的加锁方式
package cn.zengzehao.thread;
public class SyschronizedDemo3 implements Runnable {
static int count=0;
@Override
public void run() {
for (int i = 0; i < 100000000; i++) {
increase();
}
}
public synchronized void increase(){
count++;
}
public static void main(String[] args) throws InterruptedException{
Thread thread1 = new Thread(new SyschronizedDemo3());
Thread thread2 = new Thread(new SyschronizedDemo3());
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(count);
}
}
在创建线程的时候new的两个对象,而程序加锁的方式是在实例方法,每个对象都有自己的实例方法,那这样子说明程序不是在同一个锁中,故导致多线程运行的结果跟预期的是不一样的。