并发编程之synchronize
synchronized是Java中的关键字,是一种常用的线程同步锁。
用法
注意:在理解synchronized时,要知道一个核心点,synchronized锁定的不是代码,而是对象。使用synchronized时,其会申请对象的堆内存,进行锁定。
写法一
Object o = new Object(); // 锁对象
public void test01(){
//任何线程要执行以下的代码,必须先拿到锁
synchronized (o){
// doSomething...
}
}
写法二
上述写法是创建一个锁对象,其实可以自身作为锁对象。
public void test02(){
synchronized (this){
// doSomething...
}
}
写法三
同写法二。
public synchronized void test03(){
// doSomething...
}
写法四
锁定静态方法。静态方法是属于类方法,没有对象。
public synchronized static void test04(){
}
写法五
同写法四
public static void test04(){
synchronized (SynchronizeTest.class){
}
}
测试线程安全问题
演示代码:
public class TestSynch implements Runnable{
private int count = 10;
@Override
public /*synchronized*/ void run() {
count--;
System.out.println(Thread.currentThread().getName()+"count="+count);
}
public static void main(String[] args) {
TestSynch t = new TestSynch();
for (int i = 0; i < 8; i++) {
new Thread(t,"结果是"+i).start();
}
}
}
结果是:
加入synchronized:
注意事项
加锁方法和不加锁方法
public class Account {
int count = 100; // 写入数据
public synchronized void set(int s){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.count = s;
} // 读取数据
public /*synchronized*/ void get(){
System.out.println(count);
}
public static void main(String[] args) {
Account a = new Account();
new Thread(()->a.set(1)).start();
a.get();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
a.get();
}
}
在实际业务场景中,往往将读方法不加锁,写的方法加锁,这样会导致一个问题,也就是读的数据是写之前的数据,导致脏读问题。
解决方案就是,在读方法上也加锁。
加锁方法不影响不加锁方法的执行;
加锁方法访问另外一个加锁方法,一个线程拥有某个对象的锁,再次申请的时候可以再次得到这把锁(相当于锁上了两把同样的锁);子类的同步方法调用父类的同步方法也可以;
synchronized 遇到异常,锁会被释放。如果不想该锁被释放,就直接catch;
不要以字符创常量作为锁对象。
public class StringAsSynchObject {
private String stra = "hello";
private String strb = "hello";
void test1(){
synchronized (stra){
}
}
void test2(){
synchronized (strb){
}
}
}
在上述代码中,因为stra和strb 锁的是同一个对象,如果用到了同一个类库,在该类库中的代码锁定了字符串"hello",我们读不到源码,而在业务代码中也锁定了同样的字符串,这就有可能会造成非常诡异的死锁阻塞。因为程序和类库不经意用了同一把锁。(这种情况一般没办法调试)。所以通常不要字符串作为锁定对象。
synchronize 锁定的粒度越小(即锁定的业务代码越少),效率越高。
synchronize 锁释放的情况:
1)线程执行完毕;
2)线程发生异常;
3)线程进入休眠状态。
synchronize 是互斥锁,可重入锁。
wait()和notify()/notifyAll() 与 synchronize同时出现。
作者:追梦1819
原文:https://www.cnblogs.com/yanfei1819/p/10694661.html
版权声明:本文为博主原创文章,转载请附上博文链接!
最新文章
- JavaScript 控制字体大小设置
- 通过HttpWebRequest请求与HttpWebResponse响应方式发布接口与访问接口
- IOS 中openGL使用教程1(openGL ES 入门篇 | 搭建openGL环境)
- (Python)继承
- findstr 命令
- Lazarus中Base64的操作
- hadoop-1.2.0源码编译
- USACO2016 January Gold Angry Cows
- T-SQL函数及用法--转
- [置顶] android之Notification版本兼容性问题
- 解决将/etc/passwd文件中1000改为0后只能guest进入系统的问题
- ubuntu挂载的NTFS文件编译失败问题
- Docker 单主机网络
- JAVA之锁-cas
- Beta版本冲刺(四)
- python---django中url访问方法
- (博弈)Simple Game --codeforces--570B
- Truck History(prime)
- HTML中的map和area标签
- perf 工具介绍1
热门文章
- java外观模式
- [LeetCode 题解]: String to Interger (atoi)
- IIS 发布webservice 需要用户名和密码访问 解决
- HTTP杂项
- LightOJ 1234 Harmonic Number(打表 + 技巧)
- sql 统计常用的sql
- [转]解读Unity中的CG编写Shader系列6——不透明度与混合
- 《Think in Java》17~18
- CSS3水平翻转样式和background-size兼容问题
- QTREE5 - Query on a tree V(LCT)