Java线程同步
来源:互联网 发布:车万翔老师的python课 编辑:程序博客网 时间:2024/05/21 16:57
一、问题产生
假设一种场景:
有一个静态变量num,初始值为0。现在开了个线1000程,每个线程内循环1000次,每循环对num自加1,问最后的值是大于、等于还是小于1000000?
下面编写代码来看一下结果:
importjava.util.concurrent.TimeUnit;
public class Test implements Runnable{
private static int num = 0;
private void increaseNumber() {
num++;
}
@Override
public void run() {
for(inti = 1; i <=1000;i++){
increaseNumber();
System.out.println("值为" +num + ",当前" + Thread.currentThread().getName());
}
}
public static void main(String[] args) throws InterruptedException {
for (inti = 1; i <=1000;i++) {
Thread thread = new Thread(new Test());
thread.setName("线程"+i);
thread.start();
}
try {
// 等待全部子线程执行完毕
TimeUnit.SECONDS.sleep(30);
} catch(InterruptedExceptione) {
e.printStackTrace();
}
System.out.println("num的最终值为" +num);
}
}
运行结果:
分析:这里可以看出,结果小于1000000。这是因为不同的线程可能同时访问num,比如两个线程同时在某个时候访问num,这个时候num只自加了1次。若是改为先后访问,则num应该自加2次。这样导致最终结果不等于1000000。
二、同步
为了防止数据被两个或多个线程同时访问,咱们可以用synchronized关键字将数据保护起来。Synchronized的内部机理是用锁对代码段进行保护,线程A要访问这段代码时,先查看数据代码段是否处于加锁状态。若代码段处于加锁状态,说明有别的线程在访问这段代码,必须等特别的进程访问完,锁才会被释放,然后A线程才可以访问这段代码。若数据未处于加锁状态,则线程A可以访问这段代码,同时给该代码段加锁,这样别的线程要访问这块代码段就得等线程A把锁释放掉(代码段执行完时释放锁)。
同步后的代码如下:
importjava.util.concurrent.TimeUnit;
public class Test implements Runnable{
private static int num = 0;
synchronized private void increaseNumber() {
num++;
}
@Override
public void run() {
for(inti = 1; i <=1000;i++){
increaseNumber();
System.out.println("值为" +num + ",当前" + Thread.currentThread().getName());
}
}
public static void main(String[] args) throws InterruptedException {
for (inti = 1; i <=1000;i++) {
Thread thread = new Thread(new Test());
thread.setName("线程"+i);
thread.start();
}
try {
// 等待全部子线程执行完毕
TimeUnit.SECONDS.sleep(30);
} catch(InterruptedExceptione) {
e.printStackTrace();
}
System.out.println("num的最终值为" +num);
}
}
运行结果:
分析:在increateNumber()方法加上synchronized关键字后,num的值仍然不为1000000,这是什么原因呢?这要从synchronized的作用对象来分析。事实上,synchronized的作用对象是this,也就是当前对象。这样只有多个线程访问同一对象时,synchronized才会起作用。而上面代码是生成了1000个对象,即new Test()1000次,所以synchronized加跟没加都一样。
三、静态同步
若一个类的多个对象(这个例子中是1000个对象)要访问同一个数据(这里是static int num),要考虑对整个类进行同步,这样被同步的代码块就作用于该类的所有实例,从而不会被两个或多个线程(本例中一个线程就是一个实例)同时访问。Java中,是用static synchronized关键字来表示静态同步。
importjava.util.concurrent.TimeUnit;
public class Test implements Runnable{
private static int num = 0;
static synchronized private void increaseNumber() {
num++;
}
@Override
public void run() {
for(inti = 1; i <=1000;i++){
increaseNumber();
System.out.println("值为" +num + ",当前" + Thread.currentThread().getName());
}
}
public static void main(String[] args) throws InterruptedException {
for (inti = 1; i <=1000;i++) {
Thread thread = new Thread(new Test());
thread.setName("线程"+i);
thread.start();
}
try {
// 等待全部子线程执行完毕
TimeUnit.SECONDS.sleep(30);
} catch(InterruptedExceptione) {
e.printStackTrace();
}
System.out.println("num的最终值为" +num);
}
}
运行结果:
- JAVA线程-JAVA同步
- Java线程:线程的同步-同步方法
- Java线程:线程的同步-同步块
- Java线程:线程的同步-同步方法
- Java线程:线程的同步-同步块
- Java线程:线程的同步-同步方法
- Java线程:线程的同步-同步方法
- Java线程:线程的同步-同步块
- Java线程:线程的同步-同步方法
- Java线程:线程的同步-同步块
- Java线程:线程的同步-同步方法
- Java线程:线程的同步-同步块
- Java线程:线程的同步-同步方法
- Java线程:线程的同步-同步块
- Java线程:线程的同步-同步方法
- Java线程:线程的同步-同步块
- Java线程:线程的同步-同步方法
- Java线程:线程的同步-同步方法
- IntelliJ IDEA中js代码报如下警告的解决方法
- 【什么是长尾关键词(Long Tail Keyword)】
- 解析几何:第五章 二次曲线(1)圆 椭圆 双曲线
- android 代码设置、打开wifi热点及热点的连接
- MFC CxImage类的环境搭建
- Java线程同步
- 线程锁通识
- win mysql
- AndroidWidget 桌面小控件 ; 完成效果 : 桌面展示 : xx年 xx月 xx日 xx时 xx分 xx秒
- Android 6.0 (Marshmallow) 加载svg图片 报错
- iOS CoreData数据迁移-迁移管理器迁移数据
- ScrollView嵌套GridView冲突解析
- 大话设计模式-代码设计原则
- getparameter和getattribution的区别的 java详细