Java多线程
前言
当多线程访问一个公共变量会出现什么情况呢?
一、为什么要同步?
当有一个线程A,线程B访问同一个变量,不做任何处理会出现什么情况呢?
模拟一个线程a1,一个线程a2操作同一对象demo进行数据修改
代码如下(示例):
public class ThreadDemo {
public class Demo{
private int i = 100;
public int getI(){
return this.i;
}
public int doIt(int y ){
this.i= this.i-y;
return this.i;
}
}
public class RunnableDemo implements Runnable{
private Demo demo;
public RunnableDemo(Demo demo){
this.demo = demo;
}
@SneakyThrows
@Override
public void run() {
for (int i = 0 ;i<3;i++){
Thread.sleep(10);
int origin = demo.getI();
System.out.println(Thread.currentThread().getName() + "当前值" + origin + "结果值"+demo.doIt(30));
}
}
}
public static void main(String[] args) throws InterruptedException {
ThreadDemo.Demo demo = new ThreadDemo().new Demo();
ThreadDemo.RunnableDemo runnableDemo = new ThreadDemo(). new RunnableDemo(demo);
Thread t1 = new Thread(runnableDemo,"Thread-1");
Thread t2 = new Thread(runnableDemo,"Thread-2");
t1.start();
t2.start();
}
}
结果如下
问题来了:我们明明是对i进行了6次-30的操作为什么最后的值是-20
造成的原因就是两个线程不加控制的访问demo对象的值。
二、同步
Java每一个对象都有一把内置锁,当程序运行在非静态synchronized方法时候,自动获得与正在执行代码的实例(this)有关的锁,进行同步操作。当运行到synchronized方法的时候才会去获取对象锁。当一个线程获取到对象锁的时候,其他要获取对象锁的线程只能等待获得锁的线程进行锁的释放。
如果我们想要让上序示例按照执行的顺序执行,只需要在doit方法加上同步操作即可,代码如下:
public int doIt(int y ){
synchronized (this){
this.i= this.i-y;
return this.i;
}
}
同步注意的点:
- 同步只能同步方法,不能同步变量和类
- 每个对象只有一个锁
- 一个线程能获取多个锁
- 在使用同步代码块的时候,应该指定那个对象
- 同步不仅可以同步整个方法,也可以同步某一段代码
public synchronized int doIt(int y ){
this.i= this.i-y;
return this.i;
}
public synchronized int doIt(int y ){
synchronized (this){
this.i= this.i-y;
}
return this.i;
}
总结
- 线程同步是为了确保多个线程访问同一共享资源时对资源产生了破坏
- 线程同步是通过锁来解决的,每一个对象都拥有一个内部锁,这个锁与一个特定的对象关联,如果一个线程拥有了该特定对象的锁,其他线程无法访问该对象的同步方法。