廖雪峰Java11多线程编程-2线程同步-2synchronized方法
1.对Java方法进行加锁
Java使用synchronized对一个对象进行加锁,也就可使用synchronized对一个方法进行加锁。
在执行synchronized语句时,我们首先获得synchronized指定的锁。当我们添加synchronized语句块的时候,首先需要注意的是锁住那个对象?让线程自己决定锁住哪个对象,不是一个好的设计。更好的方法是通过数据封装,把同步逻辑封装到持有数据的实例中。
1.1 同步方法
由于多线程访问实例变量的时候,可能会出现同步问题,所以在add和dec方法中把this对象加锁,这样就可以保证对任何一个count实例,多线程访问的时候都是安全的。当我们对this进行加锁的时候,我们可以用synchronized来修饰这个方法,这样就把同步的代码块变为方法级别。
用synchronized修饰的方法相当于在方法内部用synchronized锁住this变量,这2种方法是完全等价的

注意:如果方法内的语句不在同步代码块内,就不再等价。

1.2 静态方法:锁住的是Class实例
如果对静态方法使用synchronized修饰符,锁住的将是当前class的Class实例。

2 示例
class Counter{
int count = 0;
public synchronized void add(int n){
count += n;
}
public synchronized void dec(int n){
count -= n;
}
public int get(){//读取一个int类型是原子操作,不需要同步
return count;
}
}
class AddThread extends Thread {
Counter counter;
public AddThread(Counter counter) {
this.counter = counter;
}
public void run() {
for (int i = 0; i < Main.LOOP; i++) {
counter.add(1);
}
}
}
class DecThread extends Thread{
Counter counter;
public DecThread(Counter counter){
this.counter = counter;
}
public void run(){
for(int i=0;i<Main.LOOP;i++){
counter.dec(1);
}
}
}
public class Main{
static final int LOOP=10000;
public static void main(String[] args) throws InterruptedException{
Counter counter = new Counter();
Thread t1 = new AddThread(counter);
Thread t2 = new DecThread(counter);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(counter.get());
}
}
3.读取方法是否需要同步?
在这个例子中,value是int类型,读取int类型是原子操作,是不需要同步的。
public int get(){ //读取一个int类型是原子操作,不用同步
return count;
}
但是把代码改一下,把value变成一个长度为2的int数组。就会发现,读方法仍然需要同步。否则在执行完result[0]=this.value[0]时,如果其他线程改变了value数组,会导致读取的结果不一致,所以读方法通常也需要同步。
public synchronized int[] get(){
int[] result = new int[2];
result[0] = this.value[0];
result[1] = this.value[1];//读取完result[0],如果其他线程改变了result[1]的值,会导致读取的结果不一致。
return result;
}
4.线程安全与非线程安全
4.1线程安全
如果一个类被设计为允许多线程正确访问, 这个类就是“线程安全”的(thread-safe),如java.lang.StringBuffer,其方法全部是用synchronized修饰的。

线程安全的类:
- 不变类:String,Integer,LocalDate。不变类因为一旦创建,实例内部的成员变量无法改变,所以多线程只能读,不能写,不需要同步,就是安全的。
- 没有成员变量的类:Math,这些工具类只提供了静态方法,没有成员变量。所以也是线程安全的。
- 正确使用synchronized的类:StringBuffer
4.2 其他的类都是非线程安全的类:
- 不能在多线程中共享实例并修改:ArrayList
- 可以在多线程中以只读方式共享
5.总结:
- 用synchronized修饰方法可以把整个方法变为同步代码块
- synchronized方法加锁对象是this
- 通过合理的设计和数据封装可以让一个类变为线程安全
- 一个类没有特殊说明,默认不是thread-safe
- 多线程能否访问某个非线程安全的实例,需要具体问题具体分析
廖雪峰Java11多线程编程-2线程同步-2synchronized方法的更多相关文章
- 廖雪峰Java11多线程编程-2线程同步-3死锁
1.线程锁可以嵌套 在多线程编程中,要执行synchronized块: 必须首先获得指定对象的锁 Java的线程锁是可重入的锁.对同一个对象,同一个线程,可以多次获取他的锁,即同一把锁可以嵌套.如以下 ...
- 廖雪峰Java11多线程编程-2线程同步-4wait和notify
wait和notify synchronized解决了多线程竞争的问题 我们可以在synchronized块中安全的对一个变量进行修改,但是它没有解决多线程协调的问题. 例如设计一个TaskQueue ...
- 廖雪峰Java11多线程编程-2线程同步-1同步代码块
1.线程安全问题 多个线程同时运行,线程调度由操作系统决定,程序本身无法决定 如果多个线程同时读写共享变量,就可能出现问题 class AddThread extends Thread{ public ...
- 廖雪峰Java11多线程编程-1线程的概念-1多线程简介
多任务 现代操作系统(windows,MacOS,Linux)都可以执行多任务: 多任务就是同时运行多个任务,例如同时开启钉钉.百度网盘.火狐.谷歌.ps等 操作系统执行多任务就是让多个任务交替执行, ...
- 廖雪峰Java11多线程编程-1线程的概念-2创建新线程
Java语言内置多线程支持: 一个Java程序实际上是一个JVM进程 JVM用一个主线程来执行main()方法 在main()方法中又可以启动多个线程 1.创建新线程 1.1 方法一:使用Thread ...
- 廖雪峰Java11多线程编程-1线程的概念-3线程的状态
1线程的状态 线程终止的的原因: run()或call()方法执行完成,线程正常结束 线程抛出一个未捕获的Exception或Error 直接调用该线程的stop()方法来结束该线程--该方法容易导致 ...
- 廖雪峰Java11多线程编程-4线程工具类-1ThreadLocal
多线程是Java实现多任务的基础: Thread ExecutorService ScheduledThreadPool Fork/Join Thread对象代表一个线程:调用Tread.curren ...
- 廖雪峰Java11多线程编程-1线程的概念-5中断线程
1.中断线程: 如果线程需要执行一个长时间任务,就可能需要中断线程.场景:从网络上下载一个100M的文件,用户在下载过程中中断下载任务的执行. 中断线程就是其他线程给该线程发一个信号,该线程收到信号后 ...
- 廖雪峰Java11多线程编程-3高级concurrent包-4Concurrent集合
Concurrent 用ReentrantLock+Condition实现Blocking Queue. Blocking Queue:当一个线程调用getTask()时,该方法内部可能让给线程进入等 ...
随机推荐
- (转)linux下装tomcat
转载于:http://www.linuxidc.com/Linux/2016-11/136959.htm (linux社区) 1 tomcat介绍 Tomcat 是由 Apache Foundatio ...
- 日常 java+雅思+训练题1
今天主要学了一些类似c中的一些语句,java也是一样类似的,只有一些点需要稍微注意一下,一些语句是新增的需要知道. 完完全全新学的知识就是class和instance的区别.如何创建实例.数据的封装. ...
- Java & 架构硬核福利,速度上车!
极客时间福利时间! 最近,栈长每周都会给大家带来极客时间的专栏拼团优惠,给错过优惠的朋友一个再次优惠上车的机会. <从0开始学架构>和<Java核心技术36讲>,这两个专栏很火 ...
- Git仓库操作命令
创建仓库 git init 在当前目录执行,会生成.git目录文件,这个和SVN一致. 提交到仓库 git commit -m "first commit" -m:表示提交描述,必 ...
- POJ1149_PIGS(网络流/EK)
PIGS Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 15721 Accepted: 7021 Description ...
- 常用指令linux总结
linux的基础操作命令: 常见命令: man 查看帮助文档 用法:man + 命令 help 查看指定命令的用法 用法: 命令 --help(有空格) tab linux下命令与文件名补全 用法:在 ...
- [JZOJ2866] 【集训队互测 2012】Bomb
题目 题目大意 给你一个有\(n\)个点的平面. 选择三个点,求两两之间曼哈顿距离和的最大值和最小值. 思考历程&正解 比赛的时候没有想太多,但感觉似乎比较水-- 首先有个很显然的性质,答案为 ...
- undertow服务器
参考地址:http://undertow.io/undertow-docs/undertow-docs-1.3.0/index.html 1.引入相关jar <dependencies> ...
- Windows netstat
{ 显示协议统计信息和当前 TCP/IP 网络连接. NETSTAT [-a] [-b] [-e] [-f] [-n] [-o] [-p proto] [-r] [-s] [-x] [-t] [int ...
- Windows ping
用法: ping [-t] [-a] [-n count] [-l size] [-f] [-i TTL] [-v TOS] [-r count] [-s count] [[-j ...