synchronized
synchronized俗称对象锁,只有获取了锁的线程才能执行被锁住的代码。
有且只有一个线程能获取对象锁。既可以让线程之间互斥访问被锁住的对象。
即使线程切换,没有锁也运行不了临界区中的代码,这样就可以保证读写的原子性,那么就一定正确。
代码示例
@Slf4j(topic = "c.Test3")
public class st3 {
static int count = 0;
static Object lock = new Object();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 5000; i++) {
synchronized (lock) {
count++;
}
}
}, "t1");
Thread t2 = new Thread(() -> {
for (int i = 0; i < 5000; i++) {
synchronized (lock){
count--;
}
}
}, "t2");
t1.start();
t2.start();
t1.join();
t2.join();
log.debug("{}",count);
}
}
面向对象改进:
@Slf4j(topic = "c.Test3")
public class st3 {
public static void main(String[] args) throws InterruptedException {
Lock lock = new Lock();
Thread t1 = new Thread(() -> {
for (int j = 0; j < 5000; j++) {
lock.incr();
}
}, "t1");
Thread t2 = new Thread(() -> {
for (int j = 0; j < 5000; j++) {
lock.decr();
}
}, "t2");
t1.start();
t2.start();
t1.join();
t2.join();
log.debug("count: {}" , lock.getCount());
}
}
class Lock{
private int count = 0;
public void incr() {
synchronized(this) {
count++;
}
}
public void decr() {
synchronized (this) {
count--;
}
}
public int getCount() {
return count;
}
}
一样的只不过,在类方法里调用,锁的是当前对象this。
方法上加synchronized
加在普通方法上是对象锁,加载静态方法上是类锁。
而不加锁的方法不受任何影响。
class Test{
public synchronized void test() {
}
}
等价于
class Test{
public void test() {
synchronized(this) {
}
}
}
class Test{
public synchronized static void test() {
}
}
等价于
class Test{
public static void test() {
synchronized(Test.class) {
}
}
}
注意:不要有误区,不要认为类锁被锁后其类对应的所有对象锁也不能再执行,类锁锁住的是类对象,也是一个对象而已,也就是Class c = xx.getClass()这个对象。
所以我认为没必要区分什么锁类锁对象啥的,都是锁一个对象。只不过一个锁的该类的对象,一个锁的该类的Class对象。不过我们通常将锁一个类叫做类锁而已。
线程八锁
"线程八锁"通常是指Java中关于多线程同步的八种情况,这些情况是基于对象锁的不同组合而产生的。这些情况包括对实例方法和静态方法的访问,以及对普通对象和Class对象的访问。
对于非静态同步方法,锁的是当前实例对象。
对于静态同步方法,锁的是当前类的Class对象。
对于同步方法块,锁的是括号里配置的对象。
下面我们就来全面解析吧。
No.1
class Number{
public synchronized void a() {
log.debug("1");
}
public synchronized void b() {
log.debug("2");
}
}
public static void main(String[] args) {
Number n1 = new Number();
new Thread(()->{ n1.a(); }).start();
new Thread(()->{ n1.b(); }).start();
}
a、b锁对象,互斥,执行顺序随机。
答案:
1、2 或
2、1
No.2
class Number{
public synchronized void a() {
sleep(1);
log.debug("1");
}
public synchronized void b() {
log.debug("2");
}
}
public static void main(String[] args) {
Number n1 = new Number();
new Thread(()->{ n1.a(); }).start();
new Thread(()->{ n1.b(); }).start();
}
a、b锁对象、互斥,执行顺序随机。
答案:1s、1、2 或
2、1s、1
No.3
class Number{
public synchronized void a() {
sleep(1);
log.debug("1");
}
public synchronized void b() {
log.debug("2");
}
public void c() {
log.debug("3");
}
}
public static void main(String[] args) {
Number n1 = new Number();
new Thread(()->{ n1.a(); }).start();
new Thread(()->{ n1.b(); }).start();
new Thread(()->{ n1.c(); }).start();
}
a、b锁对象,c普通方法,同一对象的a、b互斥、普通方法不受影响,随时可以执行。
答案:3、2、1s、1 或
3、1s、1、2 或
2、3、1s、1
No.4
class Number{
public synchronized void a() {
sleep(1);
log.debug("1");
}
public synchronized void b() {
log.debug("2");
}
}
public static void main(String[] args) {
Number n1 = new Number();
Number n2 = new Number();
new Thread(()->{ n1.a(); }).start();
new Thread(()->{ n2.b(); }).start();
}
a、b锁对象,但是调用对象不同,互不影响。
答案:
2、1s、1
No.5
class Number{
public static synchronized void a() {
sleep(1);
log.debug("1");
}
public synchronized void b() {
log.debug("2");
}
}
public static void main(String[] args) {
Number n1 = new Number();
new Thread(()->{ n1.a(); }).start();
new Thread(()->{ n1.b(); }).start();
}
a锁对象、b锁类(Class对象),互不影响。
答案:
2、1s、1
No.6
class Number{
public static synchronized void a() {
sleep(1);
log.debug("1");
}
public static synchronized void b() {
log.debug("2");
}
}
public static void main(String[] args) {
Number n1 = new Number();
new Thread(()->{ n1.a(); }).start();
new Thread(()->{ n1.b(); }).start();
}
a、b锁类,互斥,执行顺序随机。
答案:
1s、1、2 或
2、1s、1
No.7
class Number{
public static synchronized void a() {
sleep(1);
log.debug("1");
}
public synchronized void b() {
log.debug("2");
}
}
public static void main(String[] args) {
Number n1 = new Number();
Number n2 = new Number();
new Thread(()->{ n1.a(); }).start();
new Thread(()->{ n2.b(); }).start();
}
a锁类、b锁对象,但是调用对象和方法都不同,互不影响。
答案:
2、1s、1
No.8
class Number{
public static synchronized void a() {
sleep(1);
log.debug("1");
}
public static synchronized void b() {
log.debug("2");
}
}
public static void main(String[] args) {
Number n1 = new Number();
Number n2 = new Number();
new Thread(()->{ n1.a(); }).start();
new Thread(()->{ n2.b(); }).start();
}
a、b都是锁类、虽然是不同对象调用,但是他俩锁的类,互斥,执行顺序随机。
答案:
1s、1、2
2、1s、1