场景 两个线程 i++ 十万次 结果是二十万?
public class DisappearRequest1 implements Runnable{
static DisappearRequest1 instance = new DisappearRequest1();
static int i=0;
public static void main(String[] args) throws InterruptedException{
Thread t1 = new Thread(instance);
Thread t2 = new Thread(instance);
t1.start();
t2.start();
//让父线程等待子线程结束之后才能继续运行。
t1.join();
t2.join();
System.out.println(i);
}
@Override
public void run() {
// TODO Auto-generated method stub
for (int j = 0; j < 100000; j++) {
i++;
}
}
}
结果会比预计的少 原因
count++ 包含三个动作:
- 读取count
- 将count加一
- 将count值写入内存中 两个线程读到同一个count值 比如10,然后加1,都存的是11.这就是线程不安全
Synchronized的两种用法
- 对象锁
- 方法锁
@Override public void run() { method(); } public synchronized void method(){ System.out.println("我是对象锁的方法修饰符形式。我叫"+ Thread.currentThread().getName()); try { Thread.sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+" 运行结束"); } - 同步代码块锁
使用synchronized(lock/this){代码} 同一把锁 线程串行。不同锁 线程并行
Object lock1= new Object(); Object lock2= new Object(); @Override public void run() { synchronized (lock1) { System.out.println("我是lock1。 我叫"+ Thread.currentThread().getName()); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } synchronized (lock2) { System.out.println("我是lock2。 我叫"+ Thread.currentThread().getName()); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println( Thread.currentThread().getName()+" lock2运行结束"); } }
- 方法锁
- 类锁
- 修饰静态的方法
概念:Java类可能有多个对象,但只有一个class对象
类锁的第一种形式:static synchronized
public class SynchronizedClassStatic4 implements Runnable{ static SynchronizedClassStatic4 instance1 =new SynchronizedClassStatic4(); static SynchronizedClassStatic4 instance2 =new SynchronizedClassStatic4(); @Override public void run() { // TODO Auto-generated method stub method(); } public static synchronized void method(){ System.out.println("我是类锁的第一种形是:static形式 我叫"+ Thread.currentThread().getName()); try { Thread.sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"运行结束"); } public static void main(String[] args) throws InterruptedException { Thread t1= new Thread(instance1); Thread t2= new Thread(instance2); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println("over"); } } - 指定锁为Class对象 synchronized(.class)–类锁的第二种形式 ```java public void run() { method(); } public void method(){ synchronized(SynchronizedClassClass5.class){ System.out.println(“我是类锁的第二种形是:synchronized(.class)形式 我叫”+ Thread.currentThread().getName()); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+”运行结束”); }
} ```
多线程访问同步方法的七种情况(面试常考)
- 修饰静态的方法
概念:Java类可能有多个对象,但只有一个class对象
类锁的第一种形式:static synchronized
- 连个线程同时访问一个对象的同步方法 串行
- 两个线程访问的是两个对象的同步方法 并行
- 两个线程访问的是synchronized的静态方法 串行
- 同时访问同步方法与非同步方法 非同步方法不受影响
- 访问同一个类的的不同的普通同步方法 串行
- 同时访问静态synchronized和非静态synchronized的方法 非静态synchronized不受影响
- 方法抛异常后,释放锁
- synchronized的方法 调用普通方法,那普通方法不是线程安全的