Java---多线程02

上一章大概讲了线程的使用,这一篇只说说多线程里面的两个关键字:
synchronized和volatile

我们上次说到了线程安全的概念,当多个线程多同一个对象进行操作的时候,线程会出现脏数据的现象,此时,线程便签。简单来说就是两个线程同时对数据进行了操作,所以,我们需要这两个关键字对线程做一个同步:
首先:方法内的变量是线程安全的(因为方法内变量属于局部变量,本身就是私有,不存在安全)
其次:实例变量非线程安全
所以,要实现安全,就必须都能被操作,且存在次序,不可同时。

1.synchronized

synchronized:加锁
就这么简单的解释,很好理解。
用法:

用法解释
synchronized public void run(){}对一个方法进行说明synchronized
synchronized(this) {}将要上锁的语句包含进去,同步语句块
synchronized(非this对象) {}把其中的this换成其他的对象
synchronized(class) {}给对象上锁

还有其他很多其妙的用法就需要详细去挖掘了,这里暂时只想起来这几种。
下面提一提使用synchronized的一些要点以及注意:

1.1多个对象多个锁

//main类
        Mythread mythread =new Mythread();
        mythread.setName("001");
        Mythread mythread2 =new Mythread();
        mythread2.setName("002");
        Thread mythread01 =new Thread(mythread);
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        Thread mythread02 =new Thread(mythread2);

        mythread01.start();
        mythread02.start();
//Thead类
        @Override
        public void run(){
            ServiceClass serviceClass = new ServiceClass();
            serviceClass.test(this.currentThread().getName());
        }
//class类
public class ServiceClass {
    int i =1;
    public void test(String name){
    while (i<10) {
            i++;
            System.out.println("当前线程"+name+"数字"+i);
            }
    }
}

这里写图片描述
例子很简单,但是有一定意义:
尽管我是对一个class类进行操作,但是,我是两个对象,这是互不影响的,和方法中的局部变量一样,并没有数据的混乱。

  • 所以,对一个实例多个对象,会分别加锁,并不是加了一个,其他的也会加锁。
  • 对于不需要的,没有数据共享的对象,不需要加锁。

1.2synchronized方法锁

synchronized public void run(){} 

这一小节要说明的主要是:
synchronized关键字对方法加锁的时候,并不是代码块或者单单这个方法,他是对这个方法所属对象加锁,此时该对象被LOCK,其他线程需要等这个对象被解锁后,才可以访问这个线程

    synchronized public void test(String name){
    while (i<100000) {

            i++;
            System.out.println("当前线程"+name+"数字"+i);
            }
    }

    public void test02(String name){
        System.out.println(name);
    }
    int i =1;
    synchronized public void test(String name){
    while (i<100000) {

            i++;
            System.out.println("当前线程"+name+"数字"+i);
            }
    }

    synchronized public void test02(String name){
        System.out.println(name);
    }

这里写图片描述

这里的System.out.println(name);已经在之前执行了

加上synchronized:
这里写图片描述
可以看出来,线程再最后才执行。

所以我们不难得出结论:
A线程持有C对象的锁之后,B线程想要访问synchronized 声明的方法需要同步,等A线程执行完才行。
但是,B线程访问非synchronized 声明的方法可以异步访问。

1.3synchronized重入

synchronized重入的意思就是,当A线程持有B对象的锁之后,可以访问B对象的synchronized声明的所有方法。自己可以获得自己的内部锁,只要还没有释放锁

这个就不需要解释了,应该能懂,不然,肯定会死锁。

1.4异常释放锁

这个的含义就是:当出现异常的时候,锁会被自动释放

1.5同步不可以继承

synchronized关键字不可以被继承到子类,子类仍然需要加上synchronized关键字。
这个也可以不用解释了。
最明显的就是不写上synchronized关键字子类不会报错~

1.6synchronized同步代码块

synchronized同步代码块的用法是

    public void test(String name){
        synchronized (name) {
            while (i<100000) {

                i++;
                System.out.println("当前线程"+name+"数字"+i);
            }
        }
    }

其中的name一般被称为对象监视器:
同步代码块的特点是:
当一个代码块被synchronized(aaa)声明,那么线程访问这个代码块是同步的,但是不同线程访问非synchronized(aaa)的代码块是异步。

而其中还得注意,只有当对象监视器,即上文的aaa相同的同步代码块,才能实现一个对象内同步。

例如:当线程A有了synchronized(aaa)代码块的锁,线程B就无法访问其他的synchronized(aaa)上锁的代码块,但是线程B可以访问synchronized(bbb)上锁的代码块

另外,一般不推荐使用String类型的数据作为对象监视器,存在一个常量池的问题
synchronized(this)锁定的是当前对象

来做个小结:

  • synchronized同步方法和synchronized(this):
    1.对其他synchronized同步方法或者synchronized(this)代码块同步阻塞
    2.同一时间,只有一个线程可以执行synchronized同步方法中的代码
  • synchronizedsynchronized(非this):
    1,.多个线程持有对象监视器为同一对象时,只有一个线程可执行

1.6synchronized(class)同步代码块

对class对象持有锁,即就算该class有多个实现对象,是同一锁。

2.volatile

volatile是针对变量,即让一个变量对多个线程可见,实现的同步

volatile是强制的从公共内存中读取值。不从私有堆栈中取值。

3.总结

volatile远远不止这些,包括原子性,私有空间很多东西,这个先空着,以后补。

4.参考

《Java多线程编程核心技术》———–高洪岩

很简明的一本书,有兴趣可以看看。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值