同步与异步

同步与异步的介绍

同步(synchronized):同步是指一个进程在执行某个请求的时候,如果该请求需要一段时间才能返回信息,那么这个进程会一直等待下去,直到收到返回信息才继续执行下去。

异步(Asynchronous):异步是指进程不需要一直等待下去,而是继续执行下面的操作,不管其他进程的状态,当有信息返回的时候会通知进程进行处理,这样就可以提高执行的效率了,即异步是我们发出的一个请求,该请求会在后台自动发出并获取数据,然后对数据进行处理,在此过程中,我们可以继续做其他操作,不管它怎么发出请求,不关心它怎么处理数据。

解释:
同步:A线程要请求某个资源,但是此资源正在被B线程使用中,因为同步机制存在,A线程请求
不到,怎么办,A线程只能等待下去
异步:A线程要请求某个资源,但是此资源正在被B线程使用中,因为没有同步机制存在,A线程
仍然请求的到,A线程无需等待

java 通过synchronized 实现同步

一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。

public class Synchronized001 implements Runnable{
	public void run() {
          synchronized(this) {  
               for (int i = 0; i < 5; i++) {  
                    System.out.println(Thread.currentThread().getName() + " execute  loop " + i);  
               }  
          }  
     }  
     public static void main(String[] args) {  
    	 Synchronized001 t1 = new Synchronized001();  
          Thread ta = new Thread(t1, "thread1");  
          Thread tb = new Thread(t1, "thread2");  
          ta.start();  
          tb.start();  
     } 
}
结果:
thread1 execute  loop 0
thread1 execute  loop 1
thread1 execute  loop 2
thread1 execute  loop 3
thread1 execute  loop 4
thread2 execute  loop 0
thread2 execute  loop 1
thread2 execute  loop 2
thread2 execute  loop 3
thread2 execute  loop 4

二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。

public class Thread2 {

	  public void method1() { 
          synchronized(this) { 
               int i = 5; 
               while( i-- > 0) { 
                    System.out.println(Thread.currentThread().getName() + " : " + i); 
                    try { 
                         Thread.sleep(500); 
                    } catch (InterruptedException ie) { 
                    } 
               } 
          } 
     } 
     public void method2() {  
          int i = 5; 
          while( i-- > 0) { 
               System.out.println(Thread.currentThread().getName() + " : " + i); 
               try { 
                    Thread.sleep(500); 
               } catch (InterruptedException ie) { 
               } 
          } 
     } 
     public static void main(String[] args) { 
          final Thread2 thread2 = new Thread2(); 
          Thread t1 = new Thread(  new Runnable() {  public void run() {  thread2.method1();  }  }, "thread_1"  ); 
          Thread t2 = new Thread(  new Runnable() {  public void run() { thread2.method2();   }  }, "thread_2"  ); 
          t1.start(); 
          t2.start(); 
     }
thread_1 : 4
thread_2 : 4
thread_2 : 3
thread_1 : 3
thread_1 : 2
thread_2 : 2
thread_1 : 1
thread_2 : 1
thread_1 : 0
thread_2 : 0

三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。

  public void method1() { 
          synchronized(this) { 
               int i = 5; 
               while( i-- > 0) { 
                    System.out.println(Thread.currentThread().getName() + " : " + i); 
                    try { 
                         Thread.sleep(500); 
                    } catch (InterruptedException ie) { 
                    } 
               } 
          } 
     } 
     public void method2() { 
    	 synchronized(this){
          int i = 5; 
          while( i-- > 0) { 
               System.out.println(Thread.currentThread().getName() + " : " + i); 
               try { 
                    Thread.sleep(500); 
               } catch (InterruptedException ie) { 
               } 
          } 
    	 }
     } 
     public static void main(String[] args) { 
          final Thread2 thread2 = new Thread2(); 
          Thread t1 = new Thread(  new Runnable() {  public void run() {  thread2.method1();  }  }, "thread_1"  ); 
          Thread t2 = new Thread(  new Runnable() {  public void run() { thread2.method2();   }  }, "thread_2"  ); 
          t1.start(); 
          t2.start(); 

四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。

  public void method1() { 
      synchronized(this) { 
           int i = 5; 
           while( i-- > 0) { 
                System.out.println(Thread.currentThread().getName() + " : " + i); 
                try { 
                     Thread.sleep(500); 
                } catch (InterruptedException ie) { 
                } 
           } 
      } 
 } 
 public synchronized void method2() {    	
      int i = 5; 
      while( i-- > 0) { 
           System.out.println(Thread.currentThread().getName() + " : " + i); 
           try { 
                Thread.sleep(500); 
           } catch (InterruptedException ie) { 
           } 
	 }
 } 
 public static void main(String[] args) { 
      final Thread2 thread2 = new Thread2(); 
      Thread t1 = new Thread(  new Runnable() {  public void run() {  thread2.method1();  }  }, "thread_1"  ); 
      Thread t2 = new Thread(  new Runnable() {  public void run() { thread2.method2();   }  }, "thread_2"  ); 
      t1.start(); 
      t2.start(); 
 }

五、以上规则对其它对象锁同样适用

public class Thread3 {

     class Inner {
          private void m4t1() {
               int i = 5;
               while(i-- > 0) {
                    System.out.println(Thread.currentThread().getName() + " : Inner.m4t1()=" + i);
                    try {
                         Thread.sleep(500);
                    } catch(InterruptedException ie) {
                    }
               }
          }
          private  synchronized void m4t2() {
               int i = 5;
               while(i-- > 0) {
                    System.out.println(Thread.currentThread().getName() + " : Inner.m4t2()=" + i);
                    try {
                         Thread.sleep(500);
                    } catch(InterruptedException ie) {
                    }
               }
          }
     }
     private void m4t1(Inner inner) {
          synchronized(inner) { //使用对象锁
          inner.m4t1();
     }
     }
     private  void m4t2(Inner inner) {
          inner.m4t2();
     }
     public static void main(String[] args) {
          final Thread3 myt3 = new Thread3();
          final Inner inner = myt3.new Inner();
          Thread t1 = new Thread( new Runnable() {public void run() { myt3.m4t1(inner);} }, "t1");
     Thread t2 = new Thread( new Runnable() {public void run() { myt3.m4t2(inner);} }, "t2");
     t1.start();
     t2.start();
  }

java实现异步的方式

Future接口在Java 5中被引入,设计初衷是对将来某个时刻会发生的结果进行建模。它建模了一种异步计算,返回一个执行运算结果的引用,当运算结束后,这个引用被返回给调用方。
Future代表了线程执行完以后的结果,可以通过future获得执行的结果, 但是jdk1.8之前的Future有点鸡肋,并不能实现真正的异步,需要阻塞的获取结果,或者不断的轮询通常我们希望当线程执行完一些耗时的任务后,能够自动的通知我们结果,很遗憾这在原生jdk1.8之前是不支持的,但是我们可以通过第三方的库实现真正的异步回调,如果想获得耗时操作的结果,可以通过get方法获取,但是该方法会阻塞当前线程,我们可以在做完剩下的某些工作的时候调用get方法试图去获取结果,也可以调用非阻塞的方法isDone来确定操作是否完成

future 的示例

public static void main(String[] args) throws Throwable, ExecutionException {
		ExecutorService executor = Executors.newFixedThreadPool(1);
		// Future代表了线程执行完以后的结果,可以通过future获得执行的结果
		// 但是jdk1.8之前的Future有点鸡肋,并不能实现真正的异步,需要阻塞的获取结果,或者不断的轮询
		// 通常我们希望当线程执行完一些耗时的任务后,能够自动的通知我们结果,很遗憾这在原生jdk1.8之前
		// 是不支持的,但是我们可以通过第三方的库实现真正的异步回调
		Future<String> f = executor.submit(new Callable<String>() {
 
			@Override
			public String call() throws Exception {
				System.out.println("sub thread started!");
				Thread.sleep(3000);
				System.out.println("sub thread finished!");
				return "hello";
			}
		});
 
		//此处阻塞main线程
		System.out.println(f.get());
		System.out.println("main thread is blocked");
	}

Java 8新增的CompletableFuture类正是吸收了所有Google Guava中ListenableFuture和SettableFuture的特征,还提供了其它强大的功能,让Java拥有了完整的非阻塞编程模型:Future、Promise 和 Callback(在Java8之前,只有无Callback 的Future)。

CompletableFuture能够将回调放到与任务不同的线程中执行,也能将回调作为继续执行的同步函数,在与任务相同的线程中执行。它避免了传统回调最大的问题,那就是能够将控制流分离到不同的事件处理器中。

CompletableFuture弥补了Future模式的缺点。在异步的任务完成后,需要用其结果继续操作时,无需等待。可以直接通过thenAccept、thenApply、thenCompose等方式将前面异步处理的结果交给另外一个异步事件处理线程来处理。

public class JavaPromise {
	public static void main(String[] args) throws Throwable, ExecutionException {
		// 两个线程的线程池
		ExecutorService executor = Executors.newFixedThreadPool(2);
		//jdk1.8之前的实现方式
		CompletableFuture<String> future = CompletableFuture.supplyAsync(new Supplier<String>() {
			@Override
			public String get() {
				System.out.println("task started!");
				try {
					//模拟耗时操作
					Thread.sleep(2000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				return "task finished!";
			}
		}, executor);
 
		//采用lambada的实现方式
		future.thenAccept(e -> System.out.println(e + " ok"));
		
		System.out.println("main thread is running");
	}
}
  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JavaScript 是一门单线程的编程语言,意味着它在任意给定的时刻只能执行一个任务。这是因为 JavaScript 在最初设计时是作为浏览器脚本语言而诞生的,用于操作网页的 DOM(文档对象模型)。 在 JavaScript 中,任务按照它们被调用的顺序执行,这种方式称为同步执行。当一个任务执行时,其他任务必须等待它的完成才能继续执行。这种同步执行的特性可以确保数据的一致性,但也可能导致阻塞,特别是在执行耗时较长的任务时。 为了解决阻塞问题,JavaScript 引入了异步执行的概念。通过异步执行,可以让某些任务在后台执行,而不会阻塞其他任务的执行。常见的异步操作包括网络请求、文件读写和定时器等。在 JavaScript 中,通常使用回调函数、Promise、async/await 等方式来处理异步操作。 回调函数是最早被广泛使用的异步处理方式。通过将一个函数作为参数传递给异步操作,在操作完成后调用该函数来处理结果。然而,使用回调函数嵌套多层会导致代码可读性和维护性的降低,这就是所谓的"回调地狱"问题。 为了解决回调地狱问题,Promise 和 async/await 出现了。Promise 是一种用于处理异步操作的对象,它可以链式调用,避免了回调函数嵌套的问题。而 async/await 是基于 Promise 的语法糖,使异步代码看起来更像同步代码,更易于理解和编写。 总结起来,JavaScript 是单线程的,但通过异步执行可以提高程序的性能和响应速度。同步执行保证了数据的一致性,而异步执行允许在后台处理耗时操作,提高了用户体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值