zoukankan      html  css  js  c++  java
  • Java中的线程同步

    Java 中的线程同步问题:

      1. 线程同步:

          对于访问同一份资源的多个线程之间, 来进行协调的这个东西.

      2. 同步方法:

         当某个对象调用了同步方法时, 该对象上的其它同步方法必须等待该同步方法执行完毕后, 才能被执行.

      3. 同步块:

           通常将共享资源的操作放置在 synchronized 定义的区域内, 这样当其它线程也获取到这个锁时, 必须等待锁被释放, 才能进入该区域.

    Demo_1:

    class Timer {
    	private static int num = 0;
    	public void add(String name) {
    		num++;
    		try {
    			Thread.sleep(100); // 即使不写 Thread.sleep(100), 这个结果可能是对的,也有可能是错的, 不确定. 中间还是有可能被打断.
    		} catch (InterruptedException e) {
    		}
    		System.out.println(name+", 你是第 "+num+"个使用timer的线程");
    	}
    }
    class TestSync implements Runnable {
    	Timer timer = new Timer();
    	public static void main(String[] args) {
    		TestSync test = new TestSync();
    		Thread t1 = new Thread(test);
    		Thread t2 = new Thread(test);
    		t1.setName("t1");
    		t2.setName("t2");
    		t1.start();
    		t2.start();
    	}
    	@Override
    	public void run() {
    		timer.add(Thread.currentThread().getName());
    	}
    }
    

     会出现的运行结果:

    t1, 你是第 2个使用timer的线程
    t2, 你是第 2个使用timer的线程

    原因:这个线程在执行 add()方法的时候, 被另外一个线程给打断了.

    解决办法:

       num++;
       try {Thread.sleep(100); 
        } catch (InterruptedException e) {}

      上面这几句话, 应该作为一个原子性的输出, 你不应该在中途打断.

      第一种解决办法:采用同步块, 如 Demo_2

    Demo_2:

    class Timer {
    	private static int num = 0;
    	public void add(String name) {
    		synchronized(this){ // 同步块
    			num++;
    			try {Thread.sleep(100); 
    			} catch (InterruptedException e) {}
    			System.out.println(name+", 你是第 "+num+"个使用timer的线程");
    		}
    	}
    }
    class TestSync implements Runnable {
    	Timer timer = new Timer();
    	public static void main(String[] args) {
    		TestSync test = new TestSync();
    		Thread t1 = new Thread(test);
    		Thread t2 = new Thread(test);
    		t1.setName("t1");
    		t2.setName("t2");
    		t1.start();
    		t2.start();
    	}
    	@Override
    	public void run() {
    		timer.add(Thread.currentThread().getName());
    	}
    }
    // 运行结果如下:
    // t1, 你是第 1个使用timer的线程
    // t2, 你是第 2个使用timer的线程
    

    【注】:既然锁定了当前对象了, 那么这个 num 也就锁定了, 它里面的成员变量当然也锁定(互斥锁).

    【注】:锁定当前对象:这执行后面的大括号里面的语句的过程中, 一个线程的执行过程中, 不会被另外一个线程锁打断.

          一旦某个线程已经进入到锁定的区域当中, 那么你放心, 不可能有另外一个线程也在里面(锁的机制).

      第二种解决办法:采用同步块, 如 Demo_3

    Demo_3:

    class Timer {
    	private static int num = 0;
    	public synchronized void add(String name) { //同步方法
    			num++;
    			try {Thread.sleep(100); 
    			} catch (InterruptedException e) {}
    			System.out.println(name+", 你是第 "+num+"个使用timer的线程");
    	}
    }
    class TestSync implements Runnable {
    	Timer timer = new Timer();
    	public static void main(String[] args) {
    		TestSync test = new TestSync();
    		Thread t1 = new Thread(test);
    		Thread t2 = new Thread(test);
    		t1.setName("t1");
    		t2.setName("t2");
    		t1.start();
    		t2.start();
    	}
    	@Override
    	public void run() {
    		timer.add(Thread.currentThread().getName());
    	}
    }
    // 运行结果如下:
    // t1, 你是第 1个使用timer的线程
    // t2, 你是第 2个使用timer的线程
    

     分析 Demo_3 的执行过程:

      t1 开始执行, 调用 add() 方法, num++, 然后 t1 睡着了, 睡着了也没关系, t1 睡着也抱着那把锁.

      别人(t2)也进不来, 你必须等它执行完了, 你才可以继续执行.

      睡着了, 也不放开那把锁, 你也没办法.

      4. 线程同步总结:

        4.1. 在 Java 语言中, 引入了对象互斥锁的概念, 保证共享数据操作的完整性. 每个对象都对应于一个可称为"互斥锁"的标记,

           这个标记保证在任一时刻, 只有一个线程访问该对象.

        4.2. 关键字 synchronized 与对象的互斥锁联系. 当某个对象用 synchronized 来修饰时, 表明该对象在任一时刻只能由一个线程访问. 

  • 相关阅读:
    Centos 7 KVM安装win10
    python3.6小程序
    linux随手笔记(Centos为主)
    python 3.6练习题(仿购物车)
    linux mint软件安装
    pacman详解及常见问题
    manjaro安装及设置
    Ansible安装及配置
    大盘分时黄白线
    渊海子平学习
  • 原文地址:https://www.cnblogs.com/bosongokay/p/6832484.html
Copyright © 2011-2022 走看看