java 线程synchronized 线程同步

来源:互联网 发布:mac桌面壁纸设置 编辑:程序博客网 时间:2024/05/19 20:44

1、多线程的同步:

1.1、同步机制:

在多线程中,可能有多个线程试图访问一个有限的资源,必须预防这种情况的发生。所以引入了同步机制:

在线程使用一个资源时为其加锁,这样其他的线程便不能访问那个资源了,直到解锁后才可以访问。

1.2、共享成员变量的例子:

成员变量与局部变量:

成员变量:

如果一个变量是成员变量,那么多个线程对同一个对象的成员变量进行操作,这多个线程是共享一个成员变

量的。

局部变量:

如果一个变量是局部变量,那么多个线程对同一个对象进行操作,每个线程都会有一个该局部变量的拷贝。

他们之间的局部变量互不影响。

下面举例说明:

实现了Runnable的线程类:

class MyThread3 implements Runnable{ //两个线程操作同一个对象,共享成员变量 int i; @Override public void run() { //两个线程操作同一个对象,各自保存局部变量的拷贝 int i = 0;  while(i<100){ System.out.println(i); i++;  try { Thread.sleep(100); }  catch (InterruptedException e) { e.printStackTrace(); } } } }

在main方法中用两个线程操作同一个对象:

public static void main(String[] args) { MyThread3 myThread = new MyThread3(); //下面两个线程对同一个对象(Runnable的实现类对象)进行操作Thread thread = new Thread(myThread); Thread thread2 = new Thread(myThread); //各自保存局部变量的拷贝,互不影响,输出200个数字thread.start(); thread2.start(); }

这里如果把i变成成员变量,则输出100个数字。

1.3、共享资源导致的读取错误

下面举个例子,两个线程共用一个Number对象,通过Number类的getNumber方法获取数据,读取数据并

改写时,发现了重复读操作:

首先创建一个Number类:

class Number{   private int number = 10;   public String getNumber(int i){ if(number > 0){ try { Thread.sleep(100); }  catch (InterruptedException e) { e.printStackTrace(); }  number -= i;  return "取出"+i+"成功,剩余数量:"+number; } return "取出"+i+"失败,剩余数量:"+number; } }

线程类,在线程类中的私有属性包含了Number类的引用:

class MyThread4 extends Thread{   //两个线程操作同一个对象,共享成员变量Number number;  public MyThread4(Number number){ this.number = number; }@Overridepublic void run() { System.out.println(number.getNumber(8)); } }

在main函数中创建两个线程类,包含了同一个Number类实例的引用:

public static void main(String[] args) { Number number = new Number(); //两个线程操作同一个对象,共享对象number的成员变量numberMyThread4 myThread = new MyThread4(number); MyThread4 myThread2 = new MyThread4(number); myThread.start(); myThread2.start(); }

这样,当第一个线程读取Number中的number变量时先保存下来再休眠0.1秒,然后第二个线程再读取

number变量并保存,此时两个线程保存了同样的数字,在修改时,也就导致修改了同一个数字两次。

2、同步机制的实现:

2.1、使用synchronized关键字创建synchronized方法:

使用synchronized关键字,该关键字修饰的方法叫做同步方法。

Java中每个对象都有一个锁或者称为监视器,当访问某个对象的synchronized方法时,表示将该对象上锁,

而不仅仅是为该方法上锁。

这样如果一个对象的synchronized方法被某个线程执行时,其他线程无法访问该对象的任何

synchronized方法(但是可以调用其他非synchronized的方法)。直至该synchronized方法执行完。

静态的synchronized方法调用情况:

当调用一个对象的静态synchronized方法时,它锁定的并不是synchronized方法所在的对象,而是

synchronized方法所在对象对应的Class对象。这样,其他线程就不能调用该类的其他静态synchronized方

法了,但是可以调用非静态的synchronized方法。

结论:执行静态synchronized方法锁方法所在对象,执行非静态synchronized方法锁方法所在对象对应的

Class对象。
下面是多线程调用静态的方法的例子,由于锁定了方法所在对象对应的Class对象,其他线程无法调用该方法

所在对象其他的静态synchronized方法:

class Compute1{ //这时如果某个线程调用该方法,//将锁定synchronized方法所在对象对应的class对象,//而不是锁定synchronized方法所在对象public synchronized static void execute(){ for(int i = 0; i<100; i++){try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); }System.out.println("compute1:execute1 " + i++); } }public synchronized static void execute2(){ for(int i = 0; i<100; i++){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("compute1:execute2 " + i++); } } }

main方法中两个线程分别调用同一个对象的两个static synchronized方法:

public static void main(String[] args) { Compute1 com = new Compute1(); Thread thread1 = new Thread1(com); Thread thread2 = new Thread2(com); thread1.start();  thread2.start(); }

一次只能调用一个静态方法,直到执行完成。

2.2、使用synchronized创建同步代码块:

通过使用synchronized同步代码块,锁定一个对象,该对象作为可执行的标志从而达到同步的效果:

class Compute1{  //通过同步代码块锁定object1对象进行锁定了其他同样的synchronized代码块   private Object object1 = new Object();  public void execute(){ for(int i = 0; i<100; i++){ try { Thread.sleep(100); }  catch (InterruptedException e) { e.printStackTrace(); } System.out.println("compute1:execute1 " + i++); } } }  public synchronized void execute2(){ synchronized(object1){  for(int i = 0; i<100; i++){ try { Thread.sleep(100); }  catch (InterruptedException e) { e.printStackTrace(); }  System.out.println("compute1:execute2 " + i++); } } } }

如果想要使用synchronized同步代码块达到和使用synchronized方法同样的效果,可以锁定this引用:

synchronized(this){ … }

2.3、synchronized方法和synchronized同步代码块的区别:

synchronized同步代码块只是锁定了该代码块,代码块外面的代码还是可以被访问的。

synchronized方法是粗粒度的并发控制,某一个时刻只能有一个线程执行该synchronized方法。

synchronized同步代码块是细粒度的并发控制,只会将块中的代码同步,代码块之外的代码可以被其他线程

同时访问。

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 给蜂蛰了肿了痒怎么办 小米手环2没电了怎么办 小米手环2不亮了怎么办 红米3s无限重启怎么办 乐视手机1s卡顿怎么办 老公出轨了怎么办你会选择离婚吗 c盘和d盘换换了怎么办 晚上2点到3点醒怎么办 红米3s变砖了怎么办 6s锁屏密码忘了怎么办 怀孕9个月了胃疼怎么办 怀孕6个月了胃疼怎么办 孕妇胃疼怎么办4个月了 25岁欠了5万块钱怎么办 感冒嗓子疼怎么办最简单的方法 和老婆离婚了我的心好痛怎么办 4s店不给退定金怎么办 教你闪腰了后该怎么办 coolpad酷派手机开不了机怎么办 苹果5s黑屏开不了机怎么办 苹果4s的屏坏了怎么办 苹果6手机充电口接触不良怎么办 5s用久了卡顿怎么办 孕妇血糖高怎么办什么方法降最好 脚砸了肿了紫了怎么办 我想在淘宝上卖东西该怎么办 苹果手机4s开不了机怎么办 冒险岛s前出2条怎么办 狗狗又吐又拉血怎么办 小孩上网成瘾怎么办父母要怎么做 一只眼睛大一只眼睛小怎么办 带近视镜时间长了眼睛变形怎么办 联通卡2g换4g卡怎么办 上火牙疼怎么办教你立刻止疼 吃热的凉的牙疼怎么办 我买的股票退市了怎么办 如果起诉离婚另一方不出庭怎么办 10个月宝宝还没长牙怎么办 超敏c反应蛋白>5怎么办 怀孕才两个月肚子就大了怎么办 腰椎间盘突出腿疼厉害怎么办