zoukankan      html  css  js  c++  java
  • Java synchronized

    同步和多线程

    基本概念

    在Java中,同步是一种控制多线程访问共享资源的能力。当我们只允许一个线程访问共享资源时同步是最好的选择。同步一般用来解决两个问题:1.防止线程干扰2.防止一致性问题。同步分两类:1.进程(Process)同步2.线程(Thread)同步。这里我们只讨论Java中线程同步。

    当我们在一个程序中启动两个或两个以上线程时,可能会有一种情况:当多个线程试图访问相同的资源时由于并发问题会产生无法预料的结果。举个例子:如果多个线程同时写同一个文件它们可能会破坏数据,因为其中一个线程会覆盖数据,或者当一个线程打开文件的同时另一个线程正在关闭该文件。

    所以多线程要考虑同步问题,确保同一时间只有一个线程可以访问资源。这里就会有一个概念叫监视器(monitors),每个对象(object)在Java中都关联一个监视器,每个线程都可以加锁(lock)和解锁(unlock),但同一时间只有一个线程可以给监视器加锁或解锁。

    synchronized

    synchronized(objectidentifier) {
       // 访问共享变量和其它共享资源
    }
    

    这里的objectidentifier指的是获取了锁的监视器的对象。下来我们写两个例子,我们将使用两个不同的线程打印一个计数器。当没有线程同步时不是按顺序打印计数器的值,当使用synchronized()同步代码块时可以看到计数器打印的值是有序的。

    多线程示例

    没有同步代码块

    这是一个简单的例子。它可能但不一定会按顺序打印出计数器的值,这是由CPU的可用性决定的。

    class PrintDemo {
       public void printCount() {
          try {
             for(int i = 5; i > 0; i--) {
                System.out.println("Counter   ---   "  + i );
             }
          }catch (Exception e) {
             System.out.println("Thread  interrupted.");
          }
       }
    }
    
    class ThreadDemo extends Thread {
       private Thread t;
       private String threadName;
       PrintDemo  PD;
    
       ThreadDemo( String name,  PrintDemo pd) {
          threadName = name;
          PD = pd;
       }
       
       public void run() {
          PD.printCount();
          System.out.println("Thread " +  threadName + " exiting.");
       }
    
       public void start () {
          System.out.println("Starting " +  threadName );
          if (t == null) {
             t = new Thread (this, threadName);
             t.start ();
          }
       }
    }
    
    public class TestThread {
       public static void main(String args[]) {
          PrintDemo PD = new PrintDemo();
          ThreadDemo T1 = new ThreadDemo( "Thread - 1 ", PD );
          ThreadDemo T2 = new ThreadDemo( "Thread - 2 ", PD );
          T1.start();
          T2.start();
          // wait for threads to end
             try {
             T1.join();
             T2.join();
          }catch( Exception e) {
             System.out.println("Interrupted");
          }
       }
    }
    

    执行上面的代码每次运行的结果可能不一样,所以不能保证我们按顺序打印计数器。

    使用同步代码块

    下面是同样的一个例子,不过我们加了synchronized()同步代码块,这样它每次都能按顺序打印相同的值。

    class PrintDemo {
       public void printCount() {
          try {
             for(int i = 5; i > 0; i--) {
                System.out.println("Counter   ---   "  + i );
             }
          }catch (Exception e) {
             System.out.println("Thread  interrupted.");
          }
       }
    }
    
    class ThreadDemo extends Thread {
       private Thread t;
       private String threadName;
       PrintDemo  PD;
    
       ThreadDemo( String name,  PrintDemo pd) {
          threadName = name;
          PD = pd;
       }
       
       public void run() {
          synchronized(PD) {
             PD.printCount();
          }
          System.out.println("Thread " +  threadName + " exiting.");
       }
    
       public void start () {
          System.out.println("Starting " +  threadName );
          if (t == null) {
             t = new Thread (this, threadName);
             t.start ();
          }
       }
    }
    
    public class TestThread {
    
       public static void main(String args[]) {
          PrintDemo PD = new PrintDemo();
    
          ThreadDemo T1 = new ThreadDemo( "Thread - 1 ", PD );
          ThreadDemo T2 = new ThreadDemo( "Thread - 2 ", PD );
    
          T1.start();
          T2.start();
    
          // wait for threads to end
          try {
             T1.join();
             T2.join();
          }catch( Exception e) {
             System.out.println("Interrupted");
          }
       }
    }
    

    执行上面的代码每次打印的结果都一样:按顺序输出计数器的值。

    并发和并行

    Java多任务处理都会有并发执行情况,多个任务或进程共享一个CPU,并交由操作系统来完成多任务间对CPU的运行切换,以使得每个任务都有机会获得一定的时间片运行。下面是并发和并行的区别:Concurrent and Parallel Programming

    并发

    两个队列一个咖啡机。一个CPU处理多个任务逻辑,通过CPU调度算法分配计算资源,非真正的同时进行。

    并行

    两个队列两个咖啡机。多个CPU处理多个任务逻辑,多个计算任务可以同时进行。

    END

  • 相关阅读:
    ASP.NET MVC下的四种验证编程方式
    tp框架下,数据库和编辑器都是utf-8, 输出中文却还是乱码
    按拼音首字母排序
    PHP 文件导出(Excel, CSV,txt)
    RedisDesktopManager 可视化工具提示:无法加载键:Scan..
    window下redis如何查看版本号
    jQuery 防止相同的事件快速重复触发
    input中加入搜索图标
    JS搜索商品(跟外卖app店内搜索商品一样) ,keyup函数和click函数调用
    JS正则对象 RegExp(有变量的时候使用),用来匹配搜索关键字(标红)
  • 原文地址:https://www.cnblogs.com/fuos/p/7212443.html
Copyright © 2011-2022 走看看