深入理解多线程二

涉及到:

1.synchronized对象监视器为Object时的使用

2.synchronized对象监视器为Class时的使用

3.非线程安全是如何出现的.

4.关键字volatile的主要作用

5.关键字volatile与synchronized的区别与使用情况

一:同步方法:

(1).非线程安全与线程安全

非线程安全是指多个线程对同一个对象中的实例变量进行并发访问时发生,产生的后果就是"读脏",也就是

取到的数据是被更改过的.

而线程安全是获得实体变量的值是经过同步处理的,不会出现脏读的现象.

(2).方法内的变量为线程安全,也就是方法内部的私有变量是不存在"非线程安全"问题.

(3).实例变量非线程安全,多个线程共同访问一个对象中的实例变量(属性),有可能出现"非线程安全"问题.

在两个线程访问同一个对象中的同步方法时一定是线程安全的.

(4).多个对象多个锁

要先知道synchronized取得的锁是对象锁,也就是多个线程访问同一个对象是同步的(synchronized使用的"对象监视器"是一个),但不同的线程访问不同的对象就不是同步的了.

调用关键字synchronized声明的方法一定是排队运行的,另外不要忘了为什么要加锁,是因为共享,只有共享资源的读写访问才需要同步化.

注意:

A线程先持有object对象的Lock锁,B线程可以以异步的方式调用object对象中的非synchronized方法

A线程先持有object对象的Lock锁,B线程如果在这时调用object对象中的synchronized类型的方法则需要等待,也就是同步.

(5).锁重入的问题:

在使用synchronized的时候,当一个线程得到一个对象锁后,再次请求此对象锁时是可以再次得到该对象的锁的.也就是说在一个synchronized方法/块的内部调用本类的其他的synchronized方法/块时,是永远可以得到锁的.

可重入锁也支持父子类的继承环境中,也就是可以在子类的synchronized方法中调用父类的synchronized

(6).锁的释放:出现异常的时候会自动释放锁

(7).同步不具有继承性,也就是子类继承了父类的synchronized方法,但是它自己不带synchronized关键字,则该方法不是同步方法,同步方法的前面必须加上synchronized

(8).同步语句块

synchronized方法是对当前对象加锁,而synchronized代码块是对某一个对象进行加锁.

为什么要有同步语句块?是因为synchronized方法存在弊端,就是运行时间比较长,如何解决的?就是使用同步代码块,但是要注意的是这的同步代码块要锁的只是共享资源的读写,不要将整个方法内的内容锁住,当一个线程访问object的一个synchronized同步代码块时,另一个线程可以访问该object对象中的非synchronized(this)代码块.

也就是一半同步,一半异步,不在synchronized块中的就是异步执行,在synchronized块中的就是同步执行.

(9).将任意对象作为对象监视器.

使用synchronized(this)锁定的是当前对象.使用同步方法和同步代码块有两种作用:

1).对其他synchronized同步方法或synchronized(this)同步代码块调用呈阻塞状态

2).同一时间只有一个线程可以执行synchronized同步方法或synchronized(this)同步代码块中的代码

使用synchronized(非this对象x)同步代码块,优点:如果一个类中有很多synchroniized方法,这时虽然能实现同步,但会受到阻塞,影响运行效率;但如果使用同步代码块锁非this对象,则synchronized(非this)代码块中的程序与同步方法是异步的,不与其他锁同步方法争抢this锁,则可大大提高运行效率..

使用synchronized(非this对象x)同步代码块格式进行同步操作时,对象监视器必须是同一个对象,不能是方法内的对象(变量等等).

多个线程调用同一个方法是随机的,什么意思?就是 说某一个线程执行这个方法是同步的,但是多个线程同时多次调用这个方法,会出现两个线程是异步的.

(10).三个结论:

1).当多个线程同时执行synchronized(x){}同步代码块时呈现同步效果

2).当其他线程执行x对象中synchronized同步方法时呈现同步效果

3).当其他线程执行x对象方法里面的synchronized(this)代码块时也呈现同步效果

(11).静态同步synchronized方法与synchronized(class)代码块.

synchronized关键字加到static静态方法上是给Class类上锁,加到非静态方法上是给对象上锁.Class锁可以对类的所有对象实例起作用.,也就是说不同的对象也是同步执行的.

(12).数据类型String的常量池特性:

JVM中具有String常量池缓存的功能.也就是说String a = "a"; String b = "a"; System.out.println(a==b);结果是true,这就导致给String类型加锁的时候,如果String值相同,则两个线程是有相同的锁,因此在大多数情况下,同步synchronized代码块都不使用String作为锁对象,改用其他,比如说new Object()实例化一个Objectt对象,但它并不放入缓存中.

(13).同步synchronized方法无限等待与解决:

同步synchronized方法如果内部有死循环,则会使得线程无限的等待,解决办法是将synchronized方法改为非this同步代码块,使得同步锁锁的不是同一个对象,这样就可以异步执行.

(14).多线程的死锁:

不同的线程都在等待不可能被释放的锁,从而导致所有的任务都无法继续完成,简单的来说就是互相等待,只要互相等待对方释放锁就有可能出现死锁.

在设计程序的时候就要避免双方互相持有对方的锁的情况

(15).volatile关键字:使得变量在多个线程间可见.

作用是强制从公共堆栈中取得变量的值,而不是从线程私有数据栈中取得变量的值.

(16).synchronized与volatile的比较:

1).volatile是线程同步的轻量级实现,只能修饰与变量,而synchronized可以修饰方法以及代码块

2).多线程访问volatile不会发生阻塞,而synchronized会出现阻塞.

3).volatile能保证数据的可见性,但不能保证原子性;synchronized可以保证原子性,也可以间接的保证可见性,因为它会将私有内存和公共内存中的数据同步.

4).关键字volatile解决的是变量在多线程之间的可见性;而synchronized关键字解决的是多线程之间访问资源的同步

时间: 2024-08-28 20:40:38

深入理解多线程二的相关文章

理解多线程

一.理解多线程       多线程是这样一种机制,它允许在程序中并发执行多个指令流,每个指令流都称为一个线程,彼此间互相独立.线程又称为轻量级进程,它和进程一样拥有独立的执行控制,由操作系统负责调度,区别在于线程没有独立的存储空间,而是和所属进程中的其它线程共享一个存储空间,这使得线程间的通信远较进程简单.       具体到java内存模型,由于Java被设计为跨平台的语言,在内存管理上,显然也要有一个统一的模型.系统存在一个主内存(Main Memory), Java中所有变量都储存在主存中

理解ThreadLocal(二)

首先,ThreadLocal 不是用来解决共享对象的多线程访问问题的,一般情况下,通过ThreadLocal.set() 到线程中的对象是该线程自己使用的对象,其他线程是不需要访问的,也访问不到的.各个线程中访问的是不同的对象. 另外,说ThreadLocal使得各线程能够保持各自独立的一个对象,并不是通过ThreadLocal.set()来实现的,而是通过每个线程中的new 对象 的操作来创建的对象,每个线程创建一个,不是什么对象的拷贝或副本.通过ThreadLocal.set()将这个新创建

帮你理解多线程

static BOOL flag=NO; dispatch_queue_t myQueue=dispatch_queue_create("identifier", NULL); dispatch_async(myQueue, ^{ for (int i=0; i<10; i++) { NSLog(@"%d",i); } flag=YES; }); NSLog(@"before"); while (!flag){ NSLog(@"a

深入理解OOP(二):多态和继承(继承)

本文是深入浅出OOP第二篇,主要说说继承的话题. 深入理解OOP(一):多态和继承(初期绑定和编译时多态) 深入理解OOP(二):多态和继承(继承) 深入理解OOP(三):多态和继承(动态绑定和运行时多态) 深入理解OOP(四):多态和继承(C#中的抽象类) 深入理解OOP(五):C#中的访问修饰符(Public/Private/Protected/Internal/Sealed/Constants/Static and Readonly Fields) 深入理解OOP(六):枚举(实用方法)

多线程二(GCD)代码笔记

// // TWFXViewController.h // Demo_GCD // // Created by Lion User on 12-12-11. // Copyright (c) 2012年 Lion User. All rights reserved. // #import <UIKit/UIKit.h> @interface TWFXViewController : UIViewController @property (retain, nonatomic) IBOutlet

设计模式理解(二)创建型——单例、原型

设计模式理解(二)单例(Singleton)与原型(Prototype) 为什么一起写,因为懒.... 单例,就是用了面向对象语言的一些奇技淫巧,把构造函数私有了,然后用一个自身类型的静态指针作为全局唯一的实例的引用.碰到并发之类就呵呵了. 这么简单都能画个UML图,还煞有介事似的,我晕. -----------------------   分割线   ------------------------ 原型(Prototype) 我理解就是给一个类糊弄个cloneable之类的接口,让它自己决定

Android学习笔记十四.深入理解fragment(二) 之《图书详情》实战

深入理解fragment(二) 之<图书详情>实战 通过上一篇博文<深入理解fragment一>,我们学习了Android-Fragment的核心知识点.现在在此基础上,利用Fragment技术开发一款适用于大屏幕手机/平板的查找图书详情的应用软件.该项目主要在于两方面,一是Activity.Fragment的源码实现:二是,布局界面资源文件的实现. 1.res/../BookListFragment.java: 自定义类,继承于ListFragment,无需实现OnCreateV

C++ 中类的构造函数理解(二)

C++ 中类的构造函数理解(二) 写在前面 上次的笔记中简要的探索了一下C++中类的构造函数的一些特性,这篇笔记将做进一步的探索.主要是复制构造函数的使用. 复制构造函数 复制构造函数也称拷贝构造函数,它只有单个形参,且该形参是对本类类型对象的引用.其作用有以下几点: 1.根据另一个同类型的对象显示或隐式初始化一个对象 2.复制一个对象,将它作为实参传递给一个函数 3.从函数返回时复制一个对象 4.初始化顺序容器中的元素 5.根据元素初始化列表初始化数组元素 编译器合成的复制构造函数 如同默认构

openwrt上网配置的一些理解(二)

上一篇里面遇到了只能静态上网的问题,动态不行.所以再接再励,问题总是要解决的,偷懒的下场就是一直停留在菜鸟的水平. 首先分析下问题,要动态上网,首先我要明确不是动态获取不了IP,是获取了,上不了外网.那么问题就不会在lan口的配置上了,肯定是wan口,再来看我们的wan口配置.都一样,ifconfig|more,看了一下,eth1,eth2,eth3居然HWaddr都是00:A0:C9:00:00:00,不知道这样会不会影响上外网,但是肯定不对吧,所以我改了下: config interface