廖雪峰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()时,该方法内部可能让给线程进入等 ...
随机推荐
- 6.4 Data Types
Table 6-1 lists the size, representation, and range of each scalar data type for the C28x compiler. ...
- lasso数学解释
lasso:是L1正则化(绝对值) 注:坐标下降法即前向逐步线性回归 lasso算法:常用于特征选择 最小角算法,由于时间有限没有去好好研究(其实是有点复杂,尴尬)
- DIV+CSS网页布局常用的一些基础知识
CSS命名规范 一.文件命名规范 全局样式:global.css:框架布局:layout.css:字体样式:font.css:链接样式:link.css:打印样式:print.css: 二.常用类/I ...
- Java中哪个JSON库的解析速度是最快的?
JSON已经成为当前服务器与WEB应用之间数据传输的公认标准,不过正如许多我们所习以为常的事情一样,你会觉得这是理所当然的便不再深入思考 了.我们很少会去想用到的这些JSON库到底有什么不同,但事实上 ...
- MySQL 不用 Null 的理由
Null 貌似在哪里都是个头疼的问题,比如 Java 里让人头疼的 NullPointerException,为了避免猝不及防的空指针异常,千百年来程序猿们不得不在代码里小心翼翼的各种 if 判断,麻 ...
- HTML_CSS使用
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- 编译 GNU binutils
重新以 arm 用户登陆,让新设置的环境变量起作用. [arm@localhost arm]#su arm [arm@localhost arm]#cd ${SRC} [arm@localhost t ...
- Mobox企业网盘回收站文件清空与恢复的管控
1. Mobox系统提供了 个人网盘的回收站 2. Mobox系统提供了 针对公司及部门文档柜的回收站 Mobox系统对个人网盘的回收站可以做这样的限制 1) 可以通过安装程序 ,不出现 回收站 2 ...
- springboot+mybatis 非web项目构建
https://blog.csdn.net/wlittlefive/article/details/86157134 https://blog.csdn.net/ththcc/article/deta ...
- leetcode-5-最长回文子串*马拉车
方法一:动态规划 O(n2) O(n2) class Solution: def longestPalindrome(self, s: str) -> str: size = len(s) if ...